重复使用前缀++运算符时的未定义行为

msc*_*msc 23 c++ undefined-behavior c++11 c++17

我读到了关于未定义行为的答案,我看到以下声明:

++++++i;     // UB, parsed as (++(++(++i)))
Run Code Online (Sandbox Code Playgroud)

我认为这不是未定义的行为.我有一个疑问,它在C++中真的是UB吗?如果是,那怎么样?

此外,我制作程序并使用g++ prog.cpp -Wall -Wextra -std=gnu++1z -pedantic命令编译,它没有任何警告工作正常.它给出了预期的输出.

#include <iostream>
using namespace std;

int main()
{
    int i = 0;
    cout<<++++++i<<endl;
}
Run Code Online (Sandbox Code Playgroud)

use*_*001 37

在C++ 03中,它是未定义的行为.在C++ 11中它不是.各种预增量之间没有序列点.如果i是用户定义的类型,那么它将是明确定义的行为,因为那时会有一个函数调用(一个序列点).

在C++ 11中,序列点的概念被替换为之前/之后的序列.缺陷637(http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#637)提供了一个先前未定义的构造变得良好定义(i = ++i + 1)的示例.

要理解为什么它不是未定义的行为,让我们看看我们需要的部分.++i相当于i = i + 1(除了i仅评估一次).另外,如果我们替换i = i + 1inc,++(i = i + 1)变成inc = inc + 1.

[expr.ass]指出:

在所有情况下,在右和左操作数的值计算之后,以及在赋值表达式的值计算之前,对赋值进行排序.

因此,在i = i + 1计算值之前对赋值进行排序inc; 但是,在计算值之后,对赋值进行inc = inc + 1排序.没有未定义的行为,因为分配是按顺序排序的.inc


Dav*_*rtz 9

有时行为是不确定的,即使很难想象它会如何被错误处理.但是在C++之前的版本11中,这是未定义的,因为同一个对象被多次修改而没有指向插入的序列.

可以想象一个编译器通过合并所有修改来"优化"代码i.因此,每个增量都会增加原始值.但那不是重点.如果标准这样说,UB是UB.我们是否可以想象它可能失败的方式并不重要.