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?

newgre
  • 5,245
  • 4
  • 31
  • 41
  • heh, I just ran into this last night with operator+= The confusing thing to me is that reading the code you would expect that intResult1 has to be called second because it is using the value returned by intResult0 for its first argument. – Dolphin Jun 15 '09 at 16:25

4 Answers4

14

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:
What are all the common undefined behaviours that a C++ programmer should know about?

and

What are all the common undefined behaviours that a C++ programmer should know about?

Community
  • 1
  • 1
Martin York
  • 257,169
  • 86
  • 333
  • 562
13

According to Stroustrup section 6.2.2:

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

John Weldon
  • 39,849
  • 11
  • 94
  • 127
10

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())
sth
  • 222,467
  • 53
  • 283
  • 367
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
2

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
  • 273,490
  • 39
  • 460
  • 699