Weird behaviour of prefix and postfix operators

2019-05-12 01:07发布

问题:

Why is the first expression allowed, but the second not:

void test()
{
   int a;

   ++a = getSomeInt();
   a++ = getSomeInt();
}

I mean, why its forbidden for the second one to be an lvalue? The second one makes sense and the first not. In the first one we increment the variable and immediately after we gave here a new value, we lose it. That's not the case in the second expression. It makes sense to assign some value and increment the variable after that.

回答1:

The result of postfix increment is prvalue which mean pure rvalue so it is not modifiable. This is per the draft C++ standard under postfix expressions section 5.2.6 Increment and decrement which says (emphasis mine):

The value of a postfix ++ expression is the value of its operand. [ Note: the value obtained is a copy of the original value —end note ] [...] The result is a prvalue. [...]

this makes sense if you think about it, since you need to return the previous value of a it has to be a temporary value.

For completeness sake the language for prefix increment in section 5.3.2 Increment and decrement says (emphasis mine):

The operand of prefix ++ is modified by adding 1, or set to true if it is bool (this use is deprecated). The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a completely-defined object type. The result is the updated operand; it is an lvalue [...]

Update

I realized that:

++a = getSomeInt();

invokes undefined behavior in C++03, we can see that by looking at the relevant section in an older draft standard would be section 5 Expressions paragraph 4 which says:

[...]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.

so since you are modifying a more than once it is undefined. As far as I can tell this is well defined in C++11 which in section 1.9 Program execution paragraph 15 says:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] 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.

and we can see in section 5.17 Assignment and compound assignment operators paragraph 1 says:

[...] In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. [...]

but regardless, even if it is well defined expression like this:

++a = getSomeInt();

are difficult to read and maintain and should be eschewed for simpler code.

Update 2

Not sure how I missed this beofre but you are not initializing a here:

 int a;

and so it will have an indeterminate value, we don't know what it's initial value will be and performing a pre-increment on a would also be undefined behavior.