통상 증감(increment/decrement) 연산자(operator)를 사용할 때, ++i
형태를 자주 사용하게 됩니다.
그리고 나오는 이슈가 "++i
와 i++
의 차이가 무엇이냐"입니다.
결과적으로는 차이가 없습니다. 둘 다 i
에 1을 더할 뿐입니다.
하지만, 좀 더 상세하게 보면,
이 둘은 연산자 자체가 구분됩니다.
아래는 마이크로소프트 문서에 정의된 예시입니다.
https://docs.microsoft.com/ko-kr/cpp/cpp/increment-and-decrement-operator-overloading-cpp?view=msvc-170
prefix increment operator가 위에서 ++i
인 경우이고,
postfix increment operator는 i++
인 경우입니다.
// Define prefix increment operator.
Point& Point::operator++()
{
_x++;
_y++;
return *this;
}
// Define postfix increment operator.
Point Point::operator++(int)
{
Point temp = *this;
++*this;
return temp;
}
prefix를 보면 단순히 숫자에 1을 더해서 포인터를 넘겨주지만,
postfix에서는 새로운 객체를 생성한 다음에, prefix operator를 호출하고 객체를 전달합니다. 그래서 일반적으로 ++i
가 빠르다고 얘기합니다.
하지만 이건 어디 까지나 일반적인 class에 해당되는 내용이며, double, int와 같은 primitive variable에 해당되지 않습니다. 왜냐면 compiler에서 알아서 i++
은 ++i
의 형태로 처리하기 때문입니다.
테스트를 해보겠습니다.
아래 코드는 단순하게 크기가 1억인 vector를 만들고 이를 for문으로 순회(traverse)하는 코드입니다.
첫 번째는 단순히 index로 순회를 하였고 i++
로 순회를 하였고, 두 번째는 ++i
로 순회를 했습니다.
세 번째/네 번째는 iterator를 사용해서 순회를 했고 역시 it++
과 ++it
방식으로 구분을 했습니다.
위의 말이 맞다면, int로 정의된 index의 순회는 i++
, ++i
의 차이가 없어야 하며, iterator클래스를 사용한 경우인 it++
에서 복사가 일어나므로 더 느려야 합니다.
std::vector<int> test(100000000, 0);
size_t sz = test.size();
std::chrono::high_resolution_clock::time_point tt0 = std::chrono::high_resolution_clock::now();
for(int i=0;i<sz;i++ )
{
}
std::chrono::high_resolution_clock::time_point tt1 = std::chrono::high_resolution_clock::now();
for(int i=0;i<sz;++i )
{
}
std::chrono::high_resolution_clock::time_point tt2 = std::chrono::high_resolution_clock::now();
int cnt =0;
for(auto it=test.begin();it!=test.end();it++ )
{
}
std::chrono::high_resolution_clock::time_point tt3 = std::chrono::high_resolution_clock::now();
cnt =0;
for(auto it=test.begin();it!=test.end();++it)
{
}
std::chrono::high_resolution_clock::time_point tt4 = std::chrono::high_resolution_clock::now();
auto ts0 = std::chrono::duration_cast<std::chrono::milliseconds>(tt1 - tt0).count();
auto ts1 = std::chrono::duration_cast<std::chrono::milliseconds>(tt2 - tt1).count();
auto ts2 = std::chrono::duration_cast<std::chrono::milliseconds>(tt3 - tt2).count();
auto ts3 = std::chrono::duration_cast<std::chrono::milliseconds>(tt4 - tt3).count();
std::cout << ts0 <<"\n";
std::cout << ts1 <<"\n";
std::cout << ts2 <<"\n";
std::cout << ts3 <<"\n";
시간을 찍어보면 다음과 같습니다.
176
179
1347
945
조금 차이는 있지만, 첫 번째와 두 번째는 거의 비슷합니다.
반대로 iterator를 쓴 경우는 ++it
가 조금 더 빠른 것을 볼 수 있습니다. 누구나 다 알만한 내용을 한번 테스트 해보았습니다.
여기서 중요한 건, 쓸데없이 순회 목적으로 vector iterator를 쓰지 말라는 점 정도가 되겠네요.