gpt4 book ai didi

c++ - 评估顺序和未定义行为

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

在 C++11 标准的上下文中(如你所知,它不再有序列点的概念)我想了解两个最简单的示例是如何定义的。

int i = 0;

i = i++; // #0

i = ++i; // #1

有两个关于 SO 的主题解释了 C++11 上下文中的这些示例。 Here据说 #0 调用 UB 并且 #1 是明确定义的。 Here据说这两个例子都没有定义。这种模棱两可让我很困惑。我读过这篇结构良好的 reference已经三遍了,但这个话题对我来说似乎太复杂了。

.

我们来分析例子#0:i = i++;.

相应的引号是:

  • The value computation of the built-in postincrement and postdecrement operators is sequenced before its side-effect.

  • The side effect (modification of the left argument) of the built-in assignment operator and of all built-in compound assignment operators is sequenced after the value computation (but not the side effects) of both left and right arguments, and is sequenced before the value computation of the assignment expression (that is, before returning the reference to the modified object)

  • If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.

据我所知,赋值运算符的副作用与左右参数的副作用没有顺序。因此赋值运算符的副作用与 i++ 的副作用没有顺序。所以 #0 调用了一个 UB。

.

我们来分析例子#1:i =++i;.

相应的引号是:

  • The side effect of the built-in preincrement and predecrement operators is sequenced before its value computation (implicit rule due to definition as compound assignment)

  • The side effect (modification of the left argument) of the built-in assignment operator and of all built-in compound assignment operators is sequenced after the value computation (but not the side effects) of both left and right arguments, and is sequenced before the value computation of the assignment expression (that is, before returning the reference to the modified object)

  • If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.

我看不出,这个例子与 #0 有什么不同。出于与 #0 相同的原因,这对我来说似乎是一个 UB。赋值的副作用与 ++i 的副作用没有先后顺序。好像是个UB。上面喜欢的主题说它定义明确。为什么?

.

问题:如何应用引用规则来确定示例的 UB。一个尽可能简单的解释将不胜感激。谢谢!

最佳答案

由于您的引用不是直接来自标准,因此我将尝试引用标准的相关部分给出详细的答案。 “副作用”和“评估”的定义见第 1.9/12 段:

Accessing an object designated by a volatile glvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression (or a sub-expression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects.

下一个相关部分是第 1.9/15 段:

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.

现在让我们看看,如何将它应用到这两个示例中。

i = i++;

这是增量的后缀形式,您可以在第 5.2.6 段中找到它的定义。最相关的句子是:

The value computation of the ++ expression is sequenced before the modification of the operand object.

有关赋值表达式,请参见第 5.17 段。相关部分指出:

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.

使用上面的所有信息,整个表达式的评估是(标准不保证这个顺序!):

  • i++的值计算(右手边)
  • i 的值计算(左侧)
  • i的修改(++的副作用)
  • i 的修改(= 的副作用)

所有的标准保证是两个操作数的值计算在赋值表达式的值计算之前排序。但是右手边的值计算只是“读取i的值”和修改i,两个修改(副作用) 没有相互排序,我们得到未定义的行为。

第二个例子呢?

i = ++i;

这里的情况完全不同。您可以在第 5.3.2 段中找到前缀增量的定义。相关部分是:

If x is not of type bool, the expression ++x is equivalent to x+=1.

代之以,我们的表达式等价于

i = (i += 1)

在 5.17/7 中查找复合赋值运算符 += 我们得到 i += 1 等价于 i = i + 1 除了 i 只计算一次。因此,有问题的表达式最终变为

i = ( i = (i + 1))

但是我们从上面已经知道 = 的值计算是在操作数的值计算之后排序的,并且副作用是在 = 的值计算之前排序的>。所以我们得到了一个明确定义的评估顺序:

  1. 计算 i + 1 的值(和 i - 内部表达式的左侧)(#1)
  2. 启动inner =的副作用,即修改“inner”i
  3. 计算(i = i + 1)的值,即i
  4. 的"new"值
  5. 启动外层=的副作用,即修改“外层”i
  6. 计算完整表达式的值。

(#1):这里,i 只计算一次,因为 i += 1 等价于 i = i + 1除了 i 只评估一次 (5.17/7)。

关于c++ - 评估顺序和未定义行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17400137/

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