在 C++11 中的一个表达式中对同一变量进行双重赋值
Double assignment of the same variable in one expression in 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");
}
总是评估a==10
?
是的,在 C++98 和 C++11 之间发生了变化。我相信您的示例在 C++11 规则下定义良好,而在 C++98 规则下表现出未定义的行为。
举个更简单的例子,x = ++x;
在 C++98 中未定义,但在 C++11 中定义良好。请注意,x = x++;
仍未定义(后增量的副作用在表达式的评估中未排序,而前增量的副作用在相同之前排序)。
让我们将代码重写为
E1 = (E2 = E3)
其中 E1 是表达式 a
,E2 是表达式 a += 1
,E3 是表达式10
。在这里,我们使用了赋值运算符从右到左分组(C++11 标准中的 §5.17/1)。
§5.17/1 此外指出:
在所有情况下,赋值都是在左右操作数的值计算之后以及赋值表达式的值计算之前排序的。
将其应用于我们的表达式意味着我们首先必须计算子表达式 E1
和 E2 = E3
。请注意,这两个评估之间没有"之前排序"的关系,但这不会造成任何问题。
id-expression E1
的评估是微不足道的(结果本身a
)。赋值表达式E2 = E3
的计算过程如下:
首先,必须计算两个子表达式。对文字E3
的评估同样是微不足道的(给出值为 10 的 prvalue)。
(复合)赋值表达E2
的评估通过以下步骤完成:
1) a += 1
的行为等同于a = a + 1
但a
只被评估一次(§5.17/7)。在计算子表达式 a
和 1
(以任意顺序)后,将左值到重值转换应用于a
,以便读取存储在 a
中的值。
2)a
(0
)和1
的值相加(a + 1
),这种相加的结果是值1
的prvalue。
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
。
由于所有这些步骤都是明确定义的,因此整个表达式会产生一个明确定义的值。
经过一些研究,我相信你的代码行为在第 C++11 中得到了很好的定义。
$1.9/15 状态:
运算符操作数的值计算在之前排序 运算符结果的值计算。
$5.17/1 状态:
赋值运算符 (
=
) 和复合赋值运算符全部分组 从右到左。
如果我理解正确,在您的示例中
a = (a+=1) = 10;
这意味着必须在(a+=1) = 10
的值计算之前进行(a+=1)
和10
的值计算,并且在计算a = (a+=1) = 10;
之前必须完成此表达式的值计算。
$5.17/1 状态:
在所有情况下,赋值都是在左右操作数的值计算之后以及赋值表达式的值计算之前排序的。
这意味着赋值必须在值计算之前发生,因此,由于传递性,(a+=1) = 10
的评估只能在赋值a+=1
之后开始(因为它的值可能只在副作用之后计算)。
第二次和第三次作业也是如此。
另请参阅这个出色的答案,它比我更详细、更详细地解释了之前排序的关系。
- 为"adjacent"变量赋值时出现问题
- 为什么我不能在返回 const 的布尔函数中为类成员变量赋值?C++
- c++问题:给一个变量赋值后,另一个变量发生了变化
- 如何在不使用赋值运算符的情况下为动态变量赋值?
- 为什么我不能为变量赋值函数?
- 可视化的c++变量赋值使代码正常工作
- 如何为结构类型变量赋值
- 使用 boost python 从 c++ 为 python 中的类成员变量赋值
- QT变量赋值,<没有这样的值>,SIGSEGV
- C++:为全局类变量赋值
- 从类外部为类中的变量赋值
- 在 c++ 中为字符串变量赋值
- 为类中的私有静态变量赋值
- 使用类为变量赋值 (C++)
- 在编译时为变量赋值
- C ++变量赋值,这是正常的方式吗
- 在C++中为类变量赋值后声明类变量
- 了解工厂方法和静态变量赋值的返回值优化 (Visual Studio)
- 如何在 c++ 中从函数获取返回值而不为其变量赋值
- 简单的引用变量赋值导致对象的全局指针出现segfault