for (int i = 0; i < 20; i++) { }
for (int i = 0; i < 20; ++i) { }
++i
이 i++
보다 빠르다” C++하는 사람들은 한 번 쯤은 들어봤을법한 말이죠.++i
가 i++
보다 빠른지 점검 해보신 적 있으신가요?++i
가 i++
보다 빠른지 이유는 알고 계신가요? for (int i = 0; i < 20; i++) { }
003050D2 mov dword ptr [ebp-0Ch],0
003050D9 jmp __$EncStackInitStart+38h (03050E4h)
003050DB mov eax,dword ptr [ebp-0Ch]
003050DE add eax,1
003050E1 mov dword ptr [ebp-0Ch],eax
003050E4 cmp dword ptr [ebp-0Ch],14h
003050E8 jge __$EncStackInitStart+40h (03050ECh)
003050EA jmp __$EncStackInitStart+2Fh (03050DBh)
for (int i = 0; i < 20; ++i) { }
003050EC mov dword ptr [ebp-18h],0
003050F3 jmp __$EncStackInitStart+52h (03050FEh)
003050F5 mov eax,dword ptr [ebp-18h]
003050F8 add eax,1
003050FB mov dword ptr [ebp-18h],eax
003050FE cmp dword ptr [ebp-18h],14h
00305102 jge __$EncStackInitStart+5Ah (0305106h)
00305104 jmp __$EncStackInitStart+49h (03050F5h)
(VisualStudio 2019, C++ 14, Debug, x86 기준입니다)
++i
와 i++
에 해당하는 어셈블리 코드의 양이 “동일하다”는 것만 척 보면 알게됩니다.++i
나 i++
이나 성능상으로 “동일하다”는 뜻입니다.++i
가 i++
보다 빠르다고들 말하는 걸까요? 그 이유는 연산자 오버로딩에 있습니다.struct CounterStruct {
int a;
CounterStruct() : a(0) {}
CounterStruct& operator++() { a = a + 1; return *this; } // ++CounterStruct 연산
CounterStruct operator++(int) { a = a + 1; return *this; } // CounterStruct++ 연산
};
for (CounterStruct cs; cs.a < 20; cs++) { }
for (CounterStruct cs; cs.a < 20; ++cs) { }
for (CounterStruct cs; cs.a < 20; cs++) { }
00895103 lea ecx,[ebp-24h]
00895106 call CounterStruct::CounterStruct (08913A7h)
0089510B jmp __$EncStackInitStart+72h (089511Eh)
0089510D push 0 ; 추가된 코드
0089510F lea eax,[ebp-120h] ; 추가된 코드
00895115 push eax ; 추가된 코드
00895116 lea ecx,[ebp-24h]
00895119 call CounterStruct::operator++ (08913B1h)
0089511E cmp dword ptr [ebp-24h],14h
00895122 jge __$EncStackInitStart+7Ah (0895126h)
00895124 jmp __$EncStackInitStart+61h (089510Dh)
for (CounterStruct cs; cs.a < 20; ++cs) { }
00895126 lea ecx,[ebp-30h]
00895129 call CounterStruct::CounterStruct (08913A7h)
0089512E jmp __$EncStackInitStart+8Ch (0895138h)
00895130 lea ecx,[ebp-30h]
00895133 call CounterStruct::operator++ (089139Dh)
00895138 cmp dword ptr [ebp-30h],14h
0089513C jge __$EncStackInitStart+94h (0895140h)
0089513E jmp __$EncStackInitStart+84h (0895130h)
cs++
코드가 ++cs
코드보다 더 깁니다! 드디어 ++cs
가 이겼군요! 그런데 이런일이 왜 일어날까요?CounterStruct& operator++() { a = a + 1; return *this; } // ++CounterStruct 연산
CounterStruct operator++(int) { a = a + 1; return *this; } // CounterStruct++ 연산
++CounterStruct
연산자는 레퍼런스를 리턴하고 CounterStruct++
연산자는 밸류를 리턴하도록 되어있죠?CounterStruct++
함수는 실제 리턴된 밸류값을 사용하지 않더라도 “밸류”를 리턴해야 하는 함수이기에 이를 위한 비용이 추가적으로 들어가야 하는게(원론적으론) 의무입니다.++CounterStruct
연산자가 CounterStruct++
연산자보다 빠른 것이죠.++i
와 i++
의 성능차이가 존재하지 않는다.++cs
와 cs++
의 성능차이가 존재한다. ++cs
를 쓰는 것이 맞습니다.++i
가 i++
보다 빠르다고 너무 쉽게 단언하지 않았는지 생각해 봅시다.#include <cstdio>
struct CounterStruct {
int a;
CounterStruct() : a(0) {}
CounterStruct& operator++() { a = a + 1; return *this; } // ++CounterStruct 연산
CounterStruct operator++(int) { a = a + 1; return *this; } // CounterStruct++ 연산
};
int main(void) {
for (int i = 0; i < 20; i++) { }
for (int i = 0; i < 20; ++i) { }
for (CounterStruct cs; cs.a < 20; cs++) { }
for (CounterStruct cs; cs.a < 20; ++cs) { }
return 0;
}
그냥 지나가도 되지만, JellyPower님의 글에 도움을 받은 사람으로서 글을 남겨봅니다.
++i와는 달리, i++은 기존값을 보관후 값을 증가시키고 보관한 값을 return 하지만 어셈블리 차이가 없는 것은 컴파일러 최적화 때문으로 알고 있습니다.
그래서 컴파일 시간은 미미한 차이가 나지 않을까 싶구요.
위의 이유로 약간의 코드 수정도 필요해보입니다.
CounterStruct operator++(int) { auto temp = *this; ++a; return temp; }
추가로 STL의 ++iter, iter++는 클래스이기 때문에 어셈블리 차이도 보이네욤.