Compound assignment E1 op= E2 is not equivalent to E1 = E1 op E2

不羁的心 提交于 2019-12-13 16:41:09

问题


cppreference says:

the behavior of every builtin compound-assignment expression E1 op= E2 (where E1 is a modifiable lvalue expression and E2 is an rvalue expression or a braced-init-list (since C++11)) is exactly the same as the behavior of the expression E1 = E1 op E2, except that the expression E1 is evaluated only once and that it behaves as a single operation with respect to indeterminately-sequenced function calls (e.g. in f(a += b, g()), the += is either not started at all or is completed as seen from inside g())."

I want to know if this explanation is wrong (insufficient) or I'm understanding something incorrectly.

I understand there's inherent difference between E1 = E1 + E2 and E1 += E2, which is explained here:

#include<iostream>
int main() {

    int x;

    x = 1;
    x += (-1) ? 2 : 2; 
    std::cout << x << std::endl; //prints 3

    x = 1;
    x = x + (-1) ? 2 : 2;
    std::cout << x << std::endl; //prints 2

    x = 2;
    x += (-2) == 0;
    std::cout << x << std::endl; //prints 2

    x = 2;
    x = x + (-2) == 0; // prints 1

}

My guess is E1 op= E2 has the following behavior:

  • Evaluate E1 and E2 (unsure about the order) and assign result of operation between two evaluation to E1, which is (E1) = (E1) op (E2).

So would a better explanation for compound assignment operation's behavior be (E1) = (E1) op (E2)? (or E1 = E1 op (E2), because E1 only can have operator of higher precedence than assignment operator and lower precedence than op operator, without parentheses, if E1 op (E2) wants to produce different result from (E1) op (E2). Such operator whose result is a modifiable lvalue doesn't exist.)


回答1:


That quote from cppreference comes directly from the C++ Standard:

[expr.ass]/6

The behavior of an expression of the form E1 op= E2 is equivalent to E1 = E1 op E2 except that E1 is evaluated only once.
Such expressions are deprecated if E1 has volatile-qualified type; see [depr.volatile.type].
For += and -=, E1 shall either have arithmetic type or be a pointer to a possibly cv-qualified completely-defined object type.
In all other cases, E1 shall have arithmetic type.

In this context, the term expression has already been defined and E1 op= E2 being equivalent to E1 = E1 op E2 clearly doesn't mean the expressions are equivalent in their textual representation, but in their resolution (type, value and side-effects).

[A] better explanation for compound assignment operation's behavior could be (E1) = (E1) op (E2)?

I only can express my opinion: I think the cpprederence page is right to quote the Standard here, but a note could be added to make sure readers do not get it wrong.




回答2:


This is about operator precedence. + has higher precedence than the ternary conditional (and also ==). So this:

x = x + (-1) ? 2 : 2;

Is evaluated like this:

x = (x + (-1)) ? 2 : 2;

That's why you get 2 instead of 3. Same with the other sample:

x = x + (-2) == 0

is evaluated as

x = (x + (-2)) == 0 // (x + (-2)) is 0, 0 == 0 is 1

So taking the first example:

x = x + (-1) ? 2 : 2;

Here A is x and B is (x + (-1) ? 2 : 2) (x plus the result of the ternary operation)

Here, however

x += (-1) ? 2 : 2; 

A is x and B is just the result of the ternary operation. What A and B are changed due to += having a lower precedence than =. So the statement about E1 = E1 + E2 and E1 += E2 being the same is correct, but it doesn't mean that transforming E1 = E1 + E2 to E1 += E2 will never change what E1 and E2 mean. Which seems a bit misleading.




回答3:


According to the C++ Standard (8.5.18 Assignment and compound assignment operators)

7 The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is evaluated only once. In += and -=, E1 shall either have arithmetic type or be a pointer to a possibly cv-qualified completely-defined object type. In all other cases, E1 shall have arithmetic type.

And (8.5.6 Additive operators)

1 The additive operators + and - group left-to-right. The usual arithmetic conversions (8.3) are performed for operands of arithmetic or enumeration type.

These expression statements

x = x + (-1) ? 2 : 2;
x += (-2) == 0;
x = x + (-2) == 0;

are equivalent to

x = ( x - 1 ) ? 2 : 2;
x += ( -2 == 0 );
x = ( ( x - 2 ) == 0 );


来源:https://stackoverflow.com/questions/57727204/compound-assignment-e1-op-e2-is-not-equivalent-to-e1-e1-op-e2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!