重复使用前缀++运算符

时间:2017-12-01 20:05:05

标签: c++ c++11 undefined-behavior c++17

我读了这篇关于未定义行为的answer,其中我看到了以下声明:

++++++i;     // UB, parsed as (++(++(++i)))

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

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

#include <iostream>
using namespace std;

int main()
{
    int i = 0;
    cout<<++++++i<<endl;
}

2 个答案:

答案 0 :(得分: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 + 1替换为inc++(i = i + 1)将变为inc = inc + 1

[expr.ass]声明:

  

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

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

答案 1 :(得分:9)

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

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