C++11 中的新序列点

New Sequence Points in C++11

本文关键字:新序列 C++11      更新时间:2023-10-16

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

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

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

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

所以问题是:

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

在这些情况下,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++进行的两种修改是未排序的,我们得到了未定义的行为。

:注: i = (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(。

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

  • 如果i是内置类型,则这是无效的,因为i++是右值。

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