Click here to Skip to main content
14,974,887 members
Please Sign up or sign in to vote.
4.00/5 (3 votes)
See more:
C++
//Usgage 01:
int x = 15;
int y = 10;
int m = 5;
int n = 5;
int r = x++ + y++ + x++ + y++;
int r2 = x + y;

The result in r is 50.

Question is,
How Do I implement the Post-fix operator on a class having only one number and getting the same result as shown in r? I hope that is not possible... Can somebody prove that I am wrong?
Posted
Comments
Fredrik Bornander 6-Aug-13 6:34am
   
Homework?
KarstenK 6-Aug-13 6:41am
   
such code:

int r = x++ + y++ + x++ + y++;

is bad code because it is hardly to understand and maintain. A common source of nasty bugs.... ;-)
Zoltán Zörgő 6-Aug-13 6:42am
   
I am pretty sure, this code line was only for demonstration.
Sivaraman Dhamodharan 7-Aug-13 0:33am
   
Yes. It is for demonstration purpose only.

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;

C++
#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 ints.

The reason for this can be seen in the disassembly:
ASM
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
   
The Solution 2 is quite right. If you want to get the same behaviour as integer postfix you have to implement a helper class that survives the construct and performs the increment on destructor.

perhaps this code snippet can help you:
C++
template <typename TI>
class tI
{
private:
  class tIp : public tI
  {
  public:
    tIp(tI& tir,const TI ti,const TI inc):tI(ti),_tir(tir),_inc(inc){}
    ~tIp(){ _tir += _inc; }
  private:
    tI&        _tir;
    const TI  _inc;
  };
public:
              tI(const TI ti)                { _ti = ti; }
              operator const TI ()          { return _ti; }
  tI&          operator = (const tI ti)      { _ti = ti._ti; return *this; }
  tI&          operator += (const TI ti)      { _ti += ti; return *this; }
  tI          operator + (const tI ti)      { return ti._ti + _ti; }
  tIp          operator ++ (const int)        { TI ti = _ti; return tIp(*this,ti,+1); }
  tIp          operator -- (const int)        { TI ti = _ti; return tIp(*this,ti,-1); }

private:
  TI  _ti;
};

void Usgage01()
{
  //Usgage 01: 
  int x = 15;
  int y = 10;
  int m = 5;
  int n = 5;
  int r = x++ + y++ + x++ + y++;
  int r2 = x + y;

  _tprintf(__TEXT("r = %i, r2 = %i\r\n"),r,r2);
}

template <typename TI>
void UsgageT()
{
  tI<TI> x = 15;
  tI<TI> y = 10;
  tI<TI> m = 5;
  tI<TI> n = 5;
  tI<TI> r = x++ + y++ + x++ + y++;
  tI<TI> r2 = x + y;

  _tprintf(__TEXT("r = %i, r2 = %i\r\n"),(int)(TI)r,(int)(TI)r2);
}

int _tmain(int argc, _TCHAR* argv[])
{

  Usgage01();
  UsgageT<int>();
  UsgageT<unsigned int>();
  UsgageT<char>();
  UsgageT<unsigned char>();
  UsgageT<short>();
  UsgageT<unsigned short>();
  UsgageT<long>();
  UsgageT<unsigned long>();
  UsgageT<__int64>();
  UsgageT<unsigned __int64>();

  _tprintf(__TEXT("<key> ")); _gettch();
  return 0;
}


Best regards.
   
v2
Comments
Fredrik Bornander 6-Aug-13 9:10am
   
That is indeed a cool solution! +5
But isn't it still up to the compiler to decide when to destroy the temporaries?
mbue 6-Aug-13 10:07am
   
Yes. The compiler places the destructor at the end of scope. The end of scope is (;).
Regards.
You want to hear, that you can't overload such operators? Well, bad news: you can.
Take a look here: http://www.learncpp.com/cpp-tutorial/97-overloading-the-increment-and-decrement-operators/[^]
   
Comments
Maciej Los 6-Aug-13 6:53am
   
5ed!
Fredrik Bornander 6-Aug-13 7:16am
   
I think his point wasn't about being able to overload operators, but to overload them so that the result is the same.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900