0
#include <iostream>
 using namespace std;

struct X
{
    int i_Val;

    X(int iVal)
        :i_Val(iVal)
    {
    }

    X& operator++()
    {
        cout << "X::operator++()" << endl;

        ++i_Val;
        return *this;
    }

    operator int() const
    {
        return i_Val;
    }
};

const X operator+(const X& lhs, const X& rhs)
{
    cout << "operator+(const X&, const X&)" << endl;
    return lhs.i_Val + rhs.i_Val;
}

int main()
{
    X x = 5;
    X y = (++x) + (++x) + (++x);

    cout << y << endl;
}

compile and run. It produces the output:

X::operator++()
X::operator++()
X::operator++()
operator+(const X&, const X&)
operator+(const X&, const X&)
24

But I expected this:

X::operator++()
X::operator++()
operator+(const X&, const X&)
X::operator++()
operator+(const X&, const X&)
22

Who's at blame? Me or the compiler?

nakiya
  • 14,063
  • 21
  • 79
  • 118
  • 2
    You. This question is asked bidaily it seems :) - See http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points – Erik Mar 09 '11 at 11:54
  • 2
    Our compiler overlords are never wrong. – Jon Mar 09 '11 at 11:56

3 Answers3

4

This is not undefined behaviour or a dupe of some i++ = ++i misery, because an overloaded operator is a function call and an implicit sequence point is introduced.

However, it's my understanding that the order of evaluation in this context is unspecified and the compiler is free to re-order this however it likes.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Puppy
  • 144,682
  • 38
  • 256
  • 465
  • I am always at a loss with the details. How is execution of an expression with an undefined order or evaluation not undefined behavior? For sure the standard does not define a behavior for the execution of that statement. – David Rodríguez - dribeas Mar 09 '11 at 12:22
  • @David Rodriguez: Undefined behaviour produces *any* result. Executing an expression with undefined order merely produces one of a number of defined results. – Puppy Mar 09 '11 at 12:24
  • 3
    I just checked the standard (once again and I will forget in a few minutes). To be precise, the order of execution is not *undefined* but rather *unspecified*: 1.9/3 *Certain other aspects and operations of the abstract machine are described in this International Standard as unspecified (for example, order of evaluation of arguments to a function).* – David Rodríguez - dribeas Mar 09 '11 at 12:27
0

DeadMG gave the right answer.

If you like to get a 22 you can try a different compiler. ;)

icc gives me your desired output and the gcc produces the 24.

tgmath
  • 12,813
  • 2
  • 16
  • 24
  • which flag changes the behavior on that? i tried the -O flags but there was no difference. – tgmath Mar 09 '11 at 12:31
  • 1
    the point is not that any particular compiler flag *has* to change the output, it's that it is free to do so, just as introducing an extra variable somewhere might tip the register allocation algorithm in the optimiser over some threshold that results in a different order of evaluation, or the next compiler release might just do something different for the hell of it... – Tony Delroy Mar 09 '11 at 12:36
  • @TonyD: I've never heard a better explanation for the results of unspecified behaviour. Very good. – Lightness Races in Orbit Nov 03 '12 at 18:53
0

The produced output is more sound mathematically. Do everything in all parentheses once left to right, then do the parent operation.

Lee Louviere
  • 5,162
  • 30
  • 54