在C++11中,i += ++i是未定义行为吗?

12
我对我找到的解释非常有信心,它说到在C++11中,i = ++i不是未定义的。但是,我无法判断i += ++i的行为是否是明确定义的。有人愿意解答吗?

1
@KennyTM:我使用的是4.5.0版本,它会警告我即使是 i = ++i 也是未定义的。你使用的是哪个版本?你是否成功编译了 i = ++i 而没有出现警告? - Saurabh Manchanda
i = ++i 和 i += ++i 都是未定义行为。 - Armen Tsirunyan
2
@Armen:在C++0x中,i = ++i是被良好定义的。 - Saurabh Manchanda
3
@Armen: 你可能想要阅读http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#637。 - Saurabh Manchanda
@Clifford:我非常清楚,一个引起读者疑虑的代码片段永远不应该被使用,但我开始阅读C++0x的草案,这个疑问就出现了。我只是不得不问一下。 - Saurabh Manchanda
显示剩余5条评论
1个回答

9
理由是使i = ++i定义良好的推理同样可以用来证明i += ++i必须也定义良好。 i += ++i等同于i += (i += 1),新的排序规则要求在i += 1子表达式的值计算之前进行赋值。这意味着表达式i += ++i的结果必须与i = 2 * i + 1相同。
编辑:我不得不修改我的答案,因为行为毕竟是未定义的。i += ++i的行为是未定义的,因为子表达式i(左侧参数)和++i的值计算在彼此之间是无序的,并且其中一个包含对象i的更新。
这对于表达式i = ++i不是问题,因为左侧的i没有经历lvalue-to-rvalue转换,而在i += ++i的情况下会发生这种情况。
顺便说一下:在任何严肃的项目中都不要编写这样的代码。它太依赖于准确地了解排序规则,而且会有很多人既不正确地理解排序规则,也不知道DR 637导致规则的变化,也会因为缺少问题表达式的一些重要方面而被绊倒(就像我在撰写第一个版本的答案时发生的那样)。

i += ++i 相当于 i = i + ++i; 这样 i 只被计算一次。但是,它定义了哪个先被计算,是 i 还是 ++i? - Saurabh Manchanda
@Saurabh:你说得对。i = ++ii += ++i之间的区别在于左侧i的值计算,它与++i的顺序不确定。这使得结果未定义。我会相应地更新我的答案。 - Bart van Ingen Schenau
@Bart,我想知道“在所有情况下,赋值都是有序的…”具体意味着什么。究竟什么是“赋值”?复合赋值是一种赋值。我们可以说复合赋值由prvalue评估后跟随副作用组成吗? - Johannes Schaub - litb
我确实同意你的解释。但我不会打赌。而且,我希望措辞能更清晰一些。“表达式E1 op = E2”的行为等价于“E1 = E1 op E2”,除了E1只评估一次之外。”<- 我不清楚“只评估一次”究竟是什么意思。第二个表达式中的两个“E1”被不同地评估:第一个是glvalue评估,第二个是prvalue评估。 - Johannes Schaub - litb
@Johannes: "仅评估一次"意味着glvalue和prvalue的评估必须在有效地同时进行,或者prvalue的评估必须使用glvalue评估的结果。如果E1包含副作用(例如,当它是函数调用时),则副作用只能发生一次。 - Bart van Ingen Schenau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接