gpt4 book ai didi

c++ - 是什么让 i = i++ + 1;在 C++17 中合法吗?

转载 作者:IT老高 更新时间:2023-10-28 11:28:49 25 4
gpt4 key购买 nike

在你开始大喊未定义的行为之前,这明确列在N4659 (C++17)

  i = i++ + 1;        // the value of i is incremented

然而在 N3337 (C++11)

  i = i++ + 1;        // the behavior is undefined

发生了什么变化?

据我所知,来自 [N4659 basic.exec]

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a memory location is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, and they are not potentially concurrent, the behavior is undefined.

其中 定义在 [N4659 basic.type]

For trivially copyable types, the value representation is a set of bits in the object representation that determines a value, which is one discrete element of an implementation-defined set of values

来自 [N3337 basic.exec]

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. 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.

同样,值定义在 [N3337 basic.type]

For trivially copyable types, the value representation is a set of bits in the object representation that determines a value, which is one discrete element of an implementation-defined set of values.

除了提到无关紧要的并发性之外,它们是相同的,并且使用内存位置而不是标量对象,其中

Arithmetic types, enumeration types, pointer types, pointer to member types, std::nullptr_t, and cv-qualified versions of these types are collectively called scalar types.

这不会影响示例。

来自 [N4659 expr.ass]

The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand. The result in all cases is a bit-field if the left operand is a bit-field. 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. The right operand is sequenced before the left operand.

来自 [N3337 expr.ass]

The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand. The result in all cases is a bit-field if the left operand is a bit-field. 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.

唯一的区别是 N3337 中没有最后一句。

然而,最后一句话不应该有任何重要性,因为左操作数 i 既不是 “另一个副作用” 也不是 “使用与 id-expression 相同的标量对象” 是一个左值。

最佳答案

在 C++11 中,“赋值”行为,即修改 LHS 的副作用,在右操作数的 值计算 之后进行排序。请注意,这是一个相对“弱”的保证:它只产生与 RHS 的 值计算 相关的排序。它没有说明 RHS 中可能存在的 副作用,因为副作用的发生不是 值计算 的一部分。 C++11 的要求没有在赋值行为和 RHS 的任何副作用之间建立相对顺序。这就是为 UB 创造潜力的原因。

在这种情况下,唯一的希望是 RHS 中使用的特定运算符做出的任何额外保证。如果 RHS 使用前缀 ++,则特定于前缀形式 ++ 的排序属性将在此示例中节省时间。但是后缀 ++ 是另一回事:它没有做出这样的保证。在 C++11 中,= 和后缀 ++ 的副作用在此示例中最终彼此无序。那就是UB。

在C++17中,赋值运算符的规范中增加了一句:

The right operand is sequenced before the left operand.

结合上述内容,它提供了非常强大的保证。它将 RHS 中发生的 一切 (包括任何副作用)排在 LHS 中发生的 一切 之前。由于实际分配是在 LHS(和 RHS) 之后排序的,因此额外的排序将分配行为与 RHS 中存在的任何副作用完全隔离开来。这种更强的排序是消除上述 UB 的原因。

(已更新以考虑 @John Bollinger 的评论。)

关于c++ - 是什么让 i = i++ + 1;在 C++17 中合法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47702220/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com