Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Double assignment of the same variable in one expression in C++11

The C++11 standard (5.17, expr.ass) states that

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. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation

As I understand it, all expressions which are a part of the given assignment will be evaluated before the assignment itself. This rule should work even if I modify the same variable twice in the same assignment, which, I am fairly certain, was undefined behavior before.

Will the given code:

int a = 0;
a = (a+=1) = 10;

if ( a == 10 ) {
    printf("this is defined");
} else {
    printf("undefined"); 
}

always evaluate to a==10?

like image 230
Dariusz Avatar asked Oct 25 '13 10:10

Dariusz


People also ask

Is multiple assignment possible in C?

MultipleAssignment is a language property of being able to assign one value to more than one variables. It usually looks like the following: a = b = c = d = 0 // assigns all variables to 0.

Can we use multiple assignment operators in single statement?

All types of assignment operators can be mixed in a multiple assignment statement. All varieties of assignment operator have the same precedence, lower than that of any other Java operator. As with simple assignments, evaluation again takes place from right to left.

What is a double assignment?

In highly-object-oriented languages, double assignment results in the same object being assigned to multiple variables, so changes in one variable are reflected in the other.

What is assignment expression in C?

An assignment operation assigns the value of the right-hand operand to the storage location named by the left-hand operand. Therefore, the left-hand operand of an assignment operation must be a modifiable l-value. After the assignment, an assignment expression has the value of the left operand but is not an l-value.


3 Answers

Yes, there was a change between C++98 and C++11. I believe your example to be well-defined under C++11 rules, while exhibiting undefined behavior under C++98 rules.

As a simpler example, x = ++x; is undefined in C++98 but is well-defined in C++11. Note that x = x++; is still undefined (side effect of post-increment is unsequenced with the evaluation of the expression, while side effect of pre-increment is sequenced before the same).

like image 53
Igor Tandetnik Avatar answered Oct 19 '22 19:10

Igor Tandetnik


Let's rewrite your code as

E1 = (E2 = E3)

where E1 is the expression a, E2 is the expression a += 1 and E3 is the expression 10. Here we ussed, that the assignment operator groups right-to-left (§5.17/1 in C++11 Standard).

§5.17/1 moreover states:

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.

Applying this to our expression means that we first must evaluate the subexpressions E1 and E2 = E3. Note that there is no "sequenced-before" relationship between these two evaluations, but that causes no problems.

The evaluation of the id-expression E1 is trivial (the result is a itself). The evaluation of the assignment-expression E2 = E3 proceeds as follows:

First both subexpressions have to be evaluated. The evaluation of the literal E3is again trivial (gives a prvalue of value 10).

The evaluation of the (compound) assignment-expression E2 is done in the following steps:

1) The behavior of a += 1is equivalent to a = a + 1 but a is only evaluated once (§5.17/7). After evaluating the subexpressions a and 1 (in an arbitrary order), an lvalue-to-rvalue conversion is applied to a in order to read the value stored in a.

2) The values of a (which is 0) and of 1 are added (a + 1) and the result of this addition is a prvalue of value 1.

3) Before we can compute the result of the assignment a = a + 1 the value of the object the left operand refers to is replaced by the value of the right operand (§5.17/2). The result of E2 is then an lvalue refereing to the new value 1. Note that the side effect (updating the value of the left operand) is sequenced before the value computation of the assignment expression. This is §5.17/1 cited above.

Now that we have evaluated the subexpressions E2and E3, the value of the expression E2refers to is replaced by the value of E3, which is 10. Hence the result of E2 = E3 is an lvalue of value 10.

Finally, the value expression E1 refers to is replaced by the value of the expression E2 = E3, which we computed to be 10. Thus, the variable aends up to contain the value 10.

Since all these steps are well-defined, the whole expression yields a well-defined value.

like image 43
MWid Avatar answered Oct 19 '22 18:10

MWid


After doing a little research, I am convinced your codes behaviour is well defined in C++11.

$1.9/15 states:

The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.

$5.17/1 states:

The assignment operator (=) and the compound assignment operators all group right-to-left.

If I understand correctly, in your example

a = (a+=1) = 10;

this implies that the value computations of (a+=1) and 10 have to be made before the value computation of (a+=1) = 10 and the value computation of this expression has to be finished before a = (a+=1) = 10; is evaluated.

$5.17/1 states:

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.

This implies that the assignment must happen before the value computation, and therefore, due to transitivity, the evaluation of (a+=1) = 10 can only begin after the assignment a+=1 (Because its value may only be computed after the side effect).

The same is true for the second and third assignment.

See also this excellent answer, which explains the sequenced-before relation in much more detail and way better than I could.

like image 4
Philipp Lenk Avatar answered Oct 19 '22 18:10

Philipp Lenk