随着新的大学一年到来。
我们已经开始接收标准为什么++ i ++
无法按预期问题工作。
在回答了这些类型的问题之一后,我被告知新的C ++ 11标准已经改变,这不再是未定义的行为。我听说sequence points
已被sequenced before
和sequenced after
取代,但未对该主题进行深入(或根本没有)阅读。
所以我刚回答的问题是:
int i = 12;
k = ++ (++ i);
所以问题是:
C ++ 11中序列如何变化,以及它如何影响上述问题。它仍然是未定义的行为还是现在定义得很好?
答案 0 :(得分: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描述了 postfix 增量的效果。它声明:
在修改操作数对象之前,对
++
表达式的值计算进行了排序。
但是,副作用的排序(i
的修改)没有要求。这种要求也可以通过赋值表达来强加。但赋值表达式只需要在赋值之前对操作数的值计算(但不是副作用)进行排序。因此,i = ..
和i++
的两个修改都没有排序,我们得到了未定义的行为。
N.B。 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
)。
答案 1 :(得分:3)
我认为排序与您的情况无关。表达式++i++
被分组为++(i++)
,因此:
如果i
是内置类型,则无效,因为i++
是右值。
如果i
是用户定义类型并且运算符被重载,则这是嵌套函数调用,例如T::operator++(T::operator++(i), 0)
,并且在评估函数调用之前评估函数参数