It's an interesting problem you have there. I think the answer is that it depends on the compiler.
The C++ Standard does not strictly define the evaluation order for postfix operators.
So, if you have the following program for example;
#include<iostream>
class number {
private:
int value;
public:
number(const number& other) {
value = other.value;
}
number(const int initial_value) {
value = initial_value;
}
const int get_value() const {
return value;
}
number operator++(const int) {
number old(*this);
++value;
return old;
}
};
number operator+(const number& lhs, const number& rhs) {
return number(lhs.get_value() + rhs.get_value());
}
void main() {
number x = 15;
number y = 10;
number r = x++ + y++ + x++ + y++;
std::cout << "r =" << r.get_value() << std::endl;
int ix = 15;
int iy = 10;
int ir = ix++ + iy++ + ix++ + iy++;
std::cout << "ir=" << ir << std::endl;
}
It produces a value of
52 for the custom class
number
and
50 for the
int
s.
The reason for this can be seen in the disassembly:
35: number x = 15
009C1386 6A 0F push 0Fh
009C1388 8D 4D F4 lea ecx,[x]
009C138B E8 A7 FC FF FF call number::number (9C1037h)
36: number y = 10
009C1390 6A 0A push 0Ah
009C1392 8D 4D F8 lea ecx,[y]
009C1395 E8 9D FC FF FF call number::number (9C1037h)
37: number r = x++ + y++ + x++ + y++
009C139A 6A 00 push 0
009C139C 8D 45 E4 lea eax,[ebp-1Ch]
009C139F 50 push eax
009C13A0 8D 4D F8 lea ecx,[y]
009C13A3 E8 A8 FC FF FF call number::operator++ (9C1050h)
009C13A8 50 push eax
009C13A9 6A 00 push 0
009C13AB 8D 4D E0 lea ecx,[ebp-20h]
009C13AE 51 push ecx
009C13AF 8D 4D F4 lea ecx,[x]
009C13B2 E8 99 FC FF FF call number::operator++ (9C1050h)
009C13B7 50 push eax
009C13B8 6A 00 push 0
009C13BA 8D 55 DC lea edx,[ebp-24h]
009C13BD 52 push edx
009C13BE 8D 4D F8 lea ecx,[y]
009C13C1 E8 8A FC FF FF call number::operator++ (9C1050h)
009C13C6 50 push eax
009C13C7 6A 00 push 0
009C13C9 8D 45 D8 lea eax,[ebp-28h]
009C13CC 50 push eax
009C13CD 8D 4D F4 lea ecx,[x]
009C13D0 E8 7B FC FF FF call number::operator++ (9C1050h)
009C13D5 50 push eax
009C13D6 8D 4D D4 lea ecx,[ebp-2Ch]
009C13D9 51 push ecx
009C13DA E8 53 FC FF FF call operator+ (9C1032h)
009C13DF 83 C4 0C add esp,0Ch
009C13E2 50 push eax
009C13E3 8D 55 D0 lea edx,[ebp-30h]
009C13E6 52 push edx
009C13E7 E8 46 FC FF FF call operator+ (9C1032h)
009C13EC 83 C4 0C add esp,0Ch
009C13EF 50 push eax
009C13F0 8D 45 E8 lea eax,[r]
009C13F3 50 push eax
009C13F4 E8 39 FC FF FF call operator+ (9C1032h)
009C13F9 83 C4 0C add esp,0Ch
38: std::cout << "r =" << r.get_value() << std::endl
009C13FC 8B 0D 9C 82 9C 00 mov ecx,dword ptr [__imp_std::endl (9C829Ch)]
009C1402 51 push ecx
009C1403 8D 4D E8 lea ecx,[r]
009C1406 E8 3B FC FF FF call number::get_value (9C1046h)
009C140B 50 push eax
009C140C 68 30 58 9C 00 push offset std::_Iosb<int>::end+4 (9C5830h)
009C1411 8B 15 A4 82 9C 00 mov edx,dword ptr [__imp_std::cout (9C82A4h)]
009C1417 52 push edx
009C1418 E8 06 FC FF FF call std::operator<<<std::char_traits<char> > (9C1023h)
009C141D 83 C4 08 add esp,8
009C1420 8B C8 mov ecx,eax
009C1422 FF 15 A8 82 9C 00 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (9C82A8h)]
009C1428 8B C8 mov ecx,eax
009C142A FF 15 A0 82 9C 00 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (9C82A0h)]
39:
40: int ix = 15
009C1430 C7 45 F0 0F 00 00 00 mov dword ptr [ix],0Fh
41: int iy = 10
009C1437 C7 45 EC 0A 00 00 00 mov dword ptr [iy],0Ah
42: int ir = ix++ + iy++ + ix++ + iy++
009C143E 8B 45 F0 mov eax,dword ptr [ix]
009C1441 03 45 EC add eax,dword ptr [iy]
009C1444 03 45 F0 add eax,dword ptr [ix]
009C1447 03 45 EC add eax,dword ptr [iy]
009C144A 89 45 FC mov dword ptr [ir],eax
009C144D 8B 4D EC mov ecx,dword ptr [iy]
009C1450 83 C1 01 add ecx,1
009C1453 89 4D EC mov dword ptr [iy],ecx
009C1456 8B 55 F0 mov edx,dword ptr [ix]
009C1459 83 C2 01 add edx,1
009C145C 89 55 F0 mov dword ptr [ix],edx
009C145F 8B 45 EC mov eax,dword ptr [iy]
009C1462 83 C0 01 add eax,1
009C1465 89 45 EC mov dword ptr [iy],eax
009C1468 8B 4D F0 mov ecx,dword ptr [ix]
009C146B 83 C1 01 add ecx,1
009C146E 89 4D F0 mov dword ptr [ix],ecx
43:
44: std::cout << "ir=" << ir << std::endl
You can see that for the
int
scenario the adds (not the postfixs) are executed first, then when that sum is calculated four add 1 are executed, explaining the value of
50.
In the case of the
number
class, the compiler has decided to run the postfix operators first, changing the result to
52 instead.
The compiler reserves the right to do things like this in order to be able to optimize.
Hope this helps,
Fredrik