在C++ 11中的一个表达式中双重赋值相同的变量

Dar*_*usz 11 c++ variable-assignment expression-evaluation operator-precedence c++11

C++ 11标准(5.17,expr.ass)表明了这一点

在所有情况下,在右和左操作数的值计算之后,以及在赋值表达式的值计算之前,对赋值进行排序.对于不确定序列的函数调用,复合赋值的操作是单个评估

据我了解,作为给定赋值的一部分的所有表达式将在赋值本身之前进行求值.即使我在同一个赋值中修改了两次相同的变量,这条规则也应该有效,我相当肯定,之前是未定义的行为.

请问代码:

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

if ( a == 10 ) {
    printf("this is defined");
} else {
    printf("undefined"); 
}
Run Code Online (Sandbox Code Playgroud)

总是评价到a==10

Igo*_*nik 7

是的,C++ 98和C++ 11之间发生了变化.我相信你的例子在C++ 11规则下定义良好,同时在C++ 98规则下表现出未定义的行为.

作为一个更简单的例子,x = ++x;在C++ 98中未定义,但在C++ 11中定义良好.注意x = x++;仍然是未定义的(后增量的副作用在表达式的评估中未被测序,而预增量的副作用在相同之前被排序).


MWi*_*Wid 7

让我们重写您的代码

E1 = (E2 = E3)
Run Code Online (Sandbox Code Playgroud)

其中E1是表达式a,E2是表达式a += 1,E3是表达式10.在这里我们使用了,赋值运算符从右到左分组(C++ 11标准中的§5.17/ 1).

§5.17/ 1此外还说明:

在所有情况下,在右和左操作数的值计算之后,以及在赋值表达式的值计算之前,对赋值进行排序.

将此应用于我们的表达式意味着我们首先必须评估子表达式E1E2 = E3.请注意,这两个评估之间没有"按顺序排序"关系,但这不会导致任何问题.

id表达式 的评估E1是微不足道的(结果a本身).赋值表达式 的评估过程E2 = E3如下:

首先必须评估两个子表达式.文字 的评价E3再次微不足道(给出了价值10的初值).

(化合物)赋值表达式 的评估E2在以下步骤中完成:

1)行为a += 1相当于a = a + 1a只评估一次(§5.17/ 7).在评估子表达式a1(以任意顺序)之后,应用左值到右值的转换a以读取存储的值a.

2)a(是0)和的值()1(a + 1)和这个加法的结果是值的初始值1.

3)在我们计算赋值结果之前a = a + 1,左操作数引用的对象的值被右操作数的值(§5.17/ 2)替换.然后结果E2是左值引用新值1.请注意,在赋值表达式的值计算之前,会对副作用(更新左操作数的值)进行排序.这是上面引用的§5.17/ 1.

现在我们已经评估了子表达式,E2并且E3表达式E2引用的值被替换为值E3,即10.因此结果E2 = E3是价值的左值10.

最后,值表达式E1引用被表达式的值替换E2 = E3,我们计算得到它10.因此,变量a最终包含该值10.

由于所有这些步骤都是明确定义的,因此整个表达式产生了明确定义的值.