c++language-lawyerpre-increment

Why cout<<++i + ar[++i]; and cout<<ar[++i]+ ++i; give different output?


I have read about undefined behaviour.

This Link says a[i] = a[i++] leads to undefined behaviour.

But I don't understand why the output of

int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i = 0;
cout << arr[++i] + ++i << " " << i;

is 3 2

and the output of

int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i = 0;
cout << ++i + arr[++i] << " " << i;

is 4 2


Solution

  • Firstly - a[i] = a[i++] is well-defined since C++17. The sequencing rules were considerably tightened in that revision of the Standard, and the evalution of the right-hand side of an assignment operator is sequenced before the evaluation of the left hand side, meaning that all side-effects of the right-hand side must be complete before evaluation of the left-hand side begins.

    So that code is equivalent to a[i+1] = a[i]; ++i;


    Since C++17, the << operator also has left-right sequencing, i.e. the left operand is sequenced before the right operand.

    Now, ++i is defined as i+=1 and similar considerations as above apply to the evaluation of the compound assignment operator. The ++i occurs "atomically" we could say.

    However, the + operator is still unsequenced, this is defined by [intro.execution]/17:

    Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

    [...]

    If a side effect on a memory location is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, and they are not potentially concurrent, the behavior is undefined

    Unfortunately this means the behaviour of ++i + a[++i] is still undefined, because the left operand of + modifies i, and the right operand of + modifies i, and those operand evaluations are unsequenced relative to each other.


    It has previously been proposed to make + and similar operators be left-right sequenced as well, but apparently this hasn't been accepted into the Standard yet.