为什么在C ++ 11中'i = i ++ + 1`未定义的行为?
我正在阅读C ++ 11标准的n3290草案(尽可能接近实际的标准文本),并且我注意到i = i++ + 1;
产生未定义的行为。 我以前见过类似的问题,但是他们是根据旧标准(序列点)来回答的。 新标准在表达式和子表达式执行之前/之后引入了Sequencing的概念。
1.9 13之前排序的是由单个线程(1.10)执行的评估之间的不对称,传递,成对关系,这会导致这些评估之间的偏序。 给定任何两个评估A和B,如果A在B之前被排序,那么A的执行应该在B的执行之前。如果A在B之前没有被排序并且B在A之前没有被排序,那么A和B是不被序列化的。 [注意:不确定评估的执行可能会重叠。 结束注释]当A或B在A之前排序时,评估A和B的序列是不确定的,但未详细说明。 [注意:不确定的测序评估不能重叠,但可以先执行。 - 注意]
1.9 14在与每个值计算和与要评估的下一个完整表达式相关的副作用之前,对与全表达式相关的每个值计算和副作用进行排序。
1.9 15除非另有说明,否则对个体运算符和个别表达式的操作数的评估是不确定的。 [注意:在一个程序执行过程中多次评估的表达式中,对其子表达式的无序和不定序评估不需要在不同的评估中一致地执行。 - 注意]运算符结果的值计算之前,运算符操作数的值计算是排序的。 如果对标量对象的副作用不是相对于同一标量对象的其他副作用或使用相同标量对象的值进行值计算而言是未定义的,则行为是未定义的。
[ Example:
void f(int, int);
void g(int i, int* v) {
i = v[i++]; // the behavior is undefined
i = 7, i++, i++; // i becomes 9
i = i++ + 1; // the behavior is undefined
i = i + 1; // the value of i is incremented
f(i = -1, i = -1); // the behavior is undefined
}
—end example ]
我理解它的方式是这样的:
operator=
有两个操作数表达式:参照i
和i++ + 1
,它们互不相关。 第二个对i
有副作用,但是第一个对我来说似乎没有副作用或者用于计算值(或者是参考“使用相同标量对象的值进行值计算”?它实际上取决于对存储在i中的值不这么认为),所以它不是未定义的行为; operator=
执行都被排序。 它对i
有副作用,但它参考了两个操作数的顺序,所以它不是udefined行为; i++ + 1
显然是定义的行为。 我在这里错了吗? 或者是由于某些其他原因,这行不明确的行为?
PS。 标准实际上说
运算符操作数的值计算在运算符结果的值计算之前排序。
在这方面根本没有提到副作用。 然而,序列关系仅在表达式评估和评估=值计算+副作用之间定义。 所以要么我不得不假定这个草案在这里不一致,要么假设在这一行中他们的意思是评估而不是价值计算。 还是我在这里错了?
编辑:
我想我会在这里回答自己,但那是我混乱的原因:
5 1表达式是指定计算的一系列运算符和操作数。 表达式可能会导致一个值,并可能导致副作用。
所以操作符的操作数本身不是子表达式。 因此只对整个i = i++ + 1;
进行值计算i = i++ + 1;
被测序,并且没有提及副作用测序是通过标准进行的。 这就是未定义的原因。
请注意,如果例如。 operator=
被重载为给定类型(所以这将是一个implicite函数调用)它不会是未定义的行为,对吧?
这是“未定义的行为”,而不是“未详细说明”。 未定义意味着机器可以执行任何操作,包括输出空程序,随机终止或爆炸。 当然,当移植到另一个平台时,一个微妙的意外值是一个更可能的结果。
未定义的行为适用于任何情况下,两种副作用适用于相同的标量,而不会相对于彼此进行排序。 在这种情况下,副作用碰巧是相同的(在表达式之前, i
从它原始值开始递增),但是通过标准的字母,它们结合产生UB。
的副作用。未测序,因为除了,
, ?:
||
和&&
,操作员没有按照C ++ 11§5.15/ 2等术语定义排序规则:
如果评估第二个表达式,则在与第二个表达式关联的每个值计算和副作用之前对与第一个表达式关联的每个值计算和副作用进行排序。
赋值运算符确实定义了一个特殊的排序规则,§5.17/ 1:
在所有情况下,赋值都在左右操作数的值计算之后,赋值表达式的值计算之前进行排序。
这不利于i = i ++ + 1
由于副作用i ++
是不属于任何值计算的一部分。
在C ++ 03中, i = ++i + 1;
和i = i++ + 1
没有很好的定义。
但是在C ++ 11中, i = ++i + 1
变得很好定义。 但i=i++ + 1
仍然不是。
请查看此内容以了解详情排序规则和示例不一致
你正在将价值计算与副作用的解决混淆起来。 虽然必须在赋值之前计算i++
的值,但除了完整表达式的完成之外,没有任何顺序(对i
的修改)关于赋值。
对于一个对比的例子,看看逗号运算符:“每个与左表达式相关的值计算和副作用在每个值计算和与正确表达式相关的副作用之前被排序。” 注意如何分别提及价值计算和副作用。 没有这样的分配规则。
链接地址: http://www.djcxy.com/p/73211.html上一篇: Why is `i = i++ + 1` undefined behavior in C++11?
下一篇: Concatenate 3 integers to a space deliminated string in Arduino