这是未指定(未定义)的行为吗?

Ale*_*xey 5 c++

我读过这篇文章:未定义的行为和序列点,但我不知道,是否是UB.

请考虑以下示例:

#include <iostream>
class op {
public:
  explicit op(int x) {
    std::cout << "x:   " << x << std::endl;
  }

  op & operator + (const op & /* other */) {
    return *this;
  }
};

int main(int /* argc */, char * /* argv */ []) {
  int x = 0;
  op o = op(x++) + op(x++) + op(x++);

  std::cout << "res: " << x << std::endl;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我希望这样的输出(或基于评估顺序的输出的一些排列):

x:   0
x:   1
x:   2
res: 3
Run Code Online (Sandbox Code Playgroud)

gcc-4.7.1和clang-3.0给了我这样的输出,但是当我用msvc-2010编译这个例子时,我得到了输出:

x:   0
x:   0
x:   0
res: 3
Run Code Online (Sandbox Code Playgroud)

你能告诉我一些关于这种行为的信息.

Ser*_* K. 10

参数评估的顺序a + b + c是特定于编译器的.因此,调用的顺序x++将是特定于编译器的,并且在其上的中继将是未定义的行为.

使用x++++x在此类表达式中通常表示编码标准不良.最好避免它并简化表达.

在这个问题C++中编译器和评估的参数顺序你可以在C++中找到关于参数评估顺序的讨论.

以下是对C++评估顺序的解释,其中引用了C++标准:http://en.cppreference.com/w/cpp/language/eval_order

PS Bjarne Stroustrup在"The C++ Programming Language"第3版第6.2.2节中明确表示.他还给出了一个理由:

在没有对表达式评估顺序的限制的情况下,可以生成更好的代码.

(来自/sf/answers/205443661/)

  • 据我了解,编译器可能会重新排序不同优化的指令(http://stackoverflow.com/a/621556/734072),因此它可以放3个"加载"指令,然后执行`x'的增量 (2认同)
  • 我没有投票,但它不仅仅依赖于导致未定义行为的评估顺序.即使您不关心评估的顺序,代码也有UB.原因是*任何*代码具有允许的评估顺序,其中`x`在序列点之间被修改两次,具有UB.这段代码有一个允许的评估顺序,因为允许实现首先评估三个`x ++`子表达式,然后开始评估引入序列点的`op`构造函数和`op :: operator +`调用. (2认同)

Luc*_*ore 9

这是未定义的行为,因为后增量之间没有序列点x.您无法分辨哪个+将首先评估,您无法分辨哪个op(x++)将首先构建,并且您无法确定x++将执行哪个顺序.这是未定义的,只是不要编写这样的代码.