views:

338

answers:

4

Consider the following code:

typedef vector<int> intVec;

intVec& operator<<(intVec& dst, const int i) {
    dst.push_back(i);
    return dst;
}
int intResult0() {
    return 23;
}
int intResult1() {
    return 42;
}

// main
intVec v;
v << intResult0() << intResult1();

The weird thing is, that the compiler generates code, which evaluates intResult1 BEFORE intResult0 (tested with newest VC und gcc). Why would the compiler do this? By doing so, the time between evaluation and usage of the respective values is (unnecessarily) increased(?), i.e. 42 is fetched first, but pushed last to the vector. Does the C++ standard dictate this?

+9  A: 

This has nothing to do with precedence.

There is no sequence point in that last statement, so the compiler is free to evaluate the sub-expressions in whatever order it likes as long as precedence is used when combining the sub-expressions.

Note that precedence does not define an overall order of evaluation - it just defines how the operands of an expression with several operators will be combined.

For example, in the following expression:

a() * b() + c()

at some point, the compiler would need to evaluate (a() * b()) before adding in the result of c(), but there's nothing that says what order each individual function call needs to be made. The compiler can quite easily decide to call c() first, push the result on a stack, then do whatever it needs to do to evaluate the (a() * b()) expression (in which case, it might decide to evaluate b() first).

The only role that precedence plays is that the compiler is not permitted to evaluate the expression as:

a() * (b() + c())
Michael Burr
+13  A: 

The order of evaluation of sub-expressions between two sequence point is undefined.

The above code is syntactic sugar for:

v.operator<<(intResult0()).operator<<(intResult1());

The only constraint the compiler has, is that it must evaluate all parameters before a method is called and obey the precedence rules. But as long as it follows these rules each implementation is allowed to choose the details and as such this order may change between compilers.

In this example:

  • So it is perfectly legal to call intResult1() before intResult2().
  • But intResult0() must be called before the call to operator<<() (left)
  • and intResult1() must be called before the call to operator<<() (right)
  • and operator<<() (left) must be called before operator<<() (right)

See here for more info:
http://stackoverflow.com/questions/367633/what-are-all-the-common-undefined-behaviour-that-c-programmer-should-know-about/367663#367663

and

http://stackoverflow.com/questions/367633/what-are-all-the-common-undefined-behaviour-that-c-programmer-should-know-about/367690#367690

Martin York
+10  A: 

According to Stroustrup section 6.2.2:

The order of evaluation of subexpressions within an expression is undefined.

John Weldon
+2  A: 

The C++ Standard, 5:4

Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified

Steve Jessop