5

随着新的大学年的到来。
我们已经开始收到标准的为什么++ i ++不能按预期工作的问题。

在回答了其中一个类型的问题后,我被告知新的 C++11 标准已经改变,这不再是未定义的行为。我听说它sequence points已被该主题所取代sequenced beforesequenced after但尚未深入(或根本)阅读该主题。

所以我刚才回答的问题是:

int i = 12;
k = ++ (++ i);

所以问题是:

C++11 中的序列点如何变化以及它如何影响上述问题。它仍然是未定义的行为还是现在已经明确定义?

4

2 回答 2

6

这些情况下的 UB 基于 [intro.execution]/15

除非另有说明,否则单个运算符的操作数和单个表达式的子表达式的求值是无序的。[...]运算符的操作数的值计算在运算符结果的值计算之前排序。如果标量对象上的副作用相对于同一标量对象上的另一个副作用或使用同一标量对象的值的值计算是未排序的,则行为未定义。

对于++(++i): [expr.pre.incr]/1 状态++i定义为i+=1。这导致 [expr.ass]/1,它说

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

因此,对于++(++i),等价于(i+=1)+=1,内部赋值排在外部赋值之前,我们没有UB。


[intro.execution]/15 有一个 UB 的例子:

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

这里的情况有点不同(感谢Oktalist在这里指出了一个前/后缀错误)。[expr.post.incr]/1 描述了后缀增量的影响。它指出:

表达式的值计算++在操作对象的修改之前排序。

但是,对副作用的顺序(修改)没有要求i。赋值表达式也可以强加这样的要求。但是赋值表达式只需要在赋值之前对操作数的值计算(而不是副作用)进行排序。因此,通过i = ..和的两个修改i++是无序的,我们得到未定义的行为。

NBi = (i = 1);没有同样的问题:内部赋值保证 的副作用i = 1在同一个表达式的值计算之前被排序。并且该值是外部赋值所必需的,这保证了它(右操作数的值计算(i = 1))在外部赋值的副作用之前被排序。同样,i = ++i + 1;(等价于i = (i+=1) + 1;) 定义了行为。


逗号运算符是副作用排序的示例;[expr.comma]/1

与左表达式关联的每个值计算和副作用在与右表达式关联的每个值计算和副作用之前排序。

[intro.execution]/15 包括示例i = 7, i++, i++;(阅读:) (i=7), i++, i++;,它是定义的行为(i成为9)。

于 2013-09-28T17:55:45.313 回答
3

我认为排序与您的情况无关。该表达式++i++被分组为++(i++),因此:

  • 如果i是一个内置类型,那么这是无效的,因为i++它是一个右值。

  • 如果iis 是用户定义的类型并且运算符被重载,这是一个嵌套的函数调用,例如T::operator++(T::operator++(i), 0),并且函数参数在函数调用被计算之前被计算。

于 2013-09-28T17:46:01.423 回答