这些情况下的 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
)。