Consider the following C++ Standard ISO/IEC 14882:2003(E) citation (section 5, paragraph 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. 53) Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined. [Example:
i = v[i++]; // the behavior is unspecified i = 7, i++, i++; // i becomes 9 i = ++i + 1; // the behavior is unspecified i = i + 1; // the value of i is incremented
—end example]
I was surprised that i = ++i + 1
gives an undefined value of i
.
Does anybody know of a compiler implementation which does not give 2
for the following case?
int i = 0;
i = ++i + 1;
std::cout << i << std::endl;
The thing is that operator=
has two args. First one is always i
reference.
The order of evaluation does not matter in this case.
I do not see any problem except C++ Standard taboo.
Please, do not consider such cases where the order of arguments is important to evaluation. For example, ++i + i
is obviously undefined. Please, consider only my case
i = ++i + 1
.
Why does the C++ Standard prohibit such expressions?
How about, we just all agree to never, never, write code like this? If the compiler doesn't know what you want to do, how do you expect the poor sap that is following on behind you to understand what you wanted to do? Putting i++; on it's own line will not kill you.
All the above expressions invoke Undefined Behavior.
This is fine.
Read Steve Summit's C-FAQs.
Argument by analogy: If you think of operators as types of functions, then it kind of makes sense. If you had a class with an overloaded
operator=
, your assignment statement would be equivalent to something like this:(The first parameter is actually passed in implicitly via the
this
pointer, but this is just for illustration.)For a plain function call, this is obviously undefined. The value of the first argument depends on when the second argument is evaluated. However with primitive types you get away with it because the original value of
i
is simply overwritten; its value doesn't matter. But if you were doing some other magic in your ownoperator=
, then the difference could surface.Simply put: all operators act like functions, and should therefore behave according to the same notions. If
i + ++i
is undefined, theni = ++i
should be undefined as well.C/C++ defines a concept called sequence points, which refer to a point in execution where it's guaranteed that all effects of previous evaluations will have already been performed. Saying
i = ++i + 1
is undefined because it incrementsi
and also assignsi
to itself, neither of which is a defined sequence point alone. Therefore, it is unspecified which will happen first.Update for C++11 (09/30/2011)
Stop, this is well defined in C++11. It was undefined only in C++03, but C++11 is more flexible.
After that line,
i
will be 2. The reason for this change was ... because it already works in practice and it would have been more work to make it be undefined than to just leave it defined in the rules of C++11 (actually, that this works now is more of an accident than a deliberate change, so please don't do it in your code!).Straight from the horse's mouth
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#637
From
++i
, i must assigned "1", but withi = ++i + 1
, it must be assigned the value "2". Since there is no intervening sequence point, the compiler can assume that the same variable is not being written twice, so this two operations can be done in any order. so yes, the compiler would be correct if the final value is 1.