I've seen the other similar questions and read the defect about it. But I still don't get it. Why is i = ++i + 1
well-defined in C++11 when i = i++ + 1
is not? How does the standard make this well defined?
By my working out, I have the following sequenced before graph (where an arrow represents the sequenced before relationship and everything is a value computation unless otherwise specified):
i = ++i + 1 ^ | assignment (side effect on i) ^ ^ | | ☆i ++i + 1 || ^ i+=1 | ^ 1 | ★assignment (side effect on i) ^ ^ | | i 1
I've marked a side effect on i
with a black star and value computation of i
with a white star. These appear to be unsequenced with respect to each other (according to my logic). And the standard says:
If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.
The explanation in the defect report didn't help me understand. What does the lvalue-to-rvalue conversion have to do with anything? What have I gotten wrong?
... or a value computation using the value of the same scalar object ...
The important part is bolded here. The left hand side does not use the value of i
for the value computation. What is being computed is a glvalue. Only afterwards (sequenced after), the value of the object is touched and replaced.
Unfortunately this is a very subtle point :)
Well, the key moment here is that the result of ++i
is an lvalue. And in order to participate in binary +
that lvalue has to be converted to an rvalue by lvalue-to-rvalue conversion. Lvalue-to-rvalue conversion is basically an act of reading the variable i
from memory.
That means that the value of ++i
is supposed to be obtained as if it was read directly from i
. That means that conceptually the new (incremented) value of i
must be ready (must be physically stored in i
) before the evaluation of binary +
begins.
This extra sequencing is what inadvertently made the behavior defined in this case.
In C++03 there was no strict requirement to obtain the value of ++i
directly from i
. The new value could have been predicted/precalulated as i + 1
and used as an operand of binary +
even before it was physically stored in the the actual i
. Although it can be reasonably claimed that the requirement was implicitly there even in C++03 (and the fact that C++03 did not recognize its existence was a defect of C++03)
In case of i++
, the result is an rvalue. Since it is already an rvalue, there's no lvalue-to-rvalue conversion involved and there's absolutely no requirement to store it in i
before we start evaluating the binary +
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With