Xen*_*eno 15 c++ gcc compiler-bug
我已经调试了一段时间的程序,最终发现错误是由于引用没有像我想象的那样更新.
这是一个显示我遇到的问题的示例:
#include <iostream>
using namespace std;
struct Test {
Test& set(int& i){ i = 10; return *this; }
Test& print(const int& i){ cout << i << endl; return *this; }
};
int main(void){
int i = 0;
Test t;
t.set(i).print(i + 5);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我曾预料到这里的print()方法会输出15,但输出5.
编辑:10天后我才意识到,用clang输出15!这是GCC中的错误吗?
Obe*_*ron 10
让我尝试解释一下C++ 11标准.在§1.9/ 15中它说:
除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的评估是不确定的.[...]如果标量对象的副作用相对于同一标量对象的另一个副作用或使用相同标量对象的值的计算值未被排序,则行为未定义.
当然int是标量类型,并且t.set(i).print(i + 5);包含对iin set()和值计算的副作用i + 5,因此如果没有另外说明,则行为确实是未定义的.阅读§5.2.5("类成员访问"),我找不到关于.运算符的序列的任何注释.[但请看下面的编辑!]
但请注意,它当然保证set()在之前执行,print()因为后者接收前者的返回值作为(隐式this)参数.这里的罪魁祸首是print参数的值计算是未测序相对于呼叫的不确定顺序set.
编辑:在你的(@ Xeno)评论中读到答案之后,我重读了标准中的段落,事实上它后来说:
调用函数(包括其他函数调用)中的每个评估(在执行被调用函数的主体之前或之后没有特别排序)对于被调用函数的执行是不确定地排序的.
因为不定测序未未测序("未测序评估的执行可以重叠",§1.9/ 13),这确实是不未定义的行为,但"仅仅"未指定的行为,这意味着,这两个15和5是正确的输出.
因此,当<"在之前排序"并且~意味着"不确定地排序"时,我们有:
(value computations for print()'s arguments ~ execution of set()) < execution of print()