我肯定是错过了一些非常基本的东西。
我有一个简单的类,执行“就地”操作,然后返回对this的引用(这允许我链接不同的操作)。当我打印到一个std::ostream时,我会看到一个意想不到的输出。下面的代码将帮助我解释。
#include<iostream>
struct Container {
Container(int x, int y, int z)
: m_data{x, y, z} { }
int operator()(size_t index) const {
return m_data[index];
}
Container& shift() {
int tmp = m_data[0];
m_data[0] = m_data[1];
m_data[1] = m_data[2];
m_data[2] = tmp;
return *this;
}
int m_data[3];
};
std::ostream& operator<<(std::ostream& os, const Container& c) {
os<<"["<<c(0)<<", "<<c(1)<<", "<<c(2)<<"]";
return os;
}
int main() {
std::cout<<std::endl<<"Behaviour Line-By-Line (works as expected)"<<std::endl;
Container d(1, 2, 3);
std::cout<<"Container as built: "<<d<<std::endl;
d.shift();
std::cout<<"Container after first shift: "<<d<<std::endl;
d.shift();
std::cout<<"Container after second shift: "<<d<<std::endl;
std::cout<<std::endl<<"Behaviour On The Same Line (not as expected)"<<std::endl;
Container c(1, 2, 3);
std::cout<<"Container as built: "<<c<<std::endl
<<"Container after first shift: "<<c.shift()<<std::endl
<<"Container after second shift: "<<c.shift()<<std::endl;
return 0;
}编译(OS 10.7.4使用GCC 4.8.1)并运行:
$ g++ example.cpp -std=c++11 -Wall -Wextra
$ ./a.out
Behaviour Line-By-Line (works as expected)
Container as built: [1, 2, 3]
Container after first shift: [2, 3, 1]
Container after second shift: [3, 1, 2]
Behaviour On The Same Line (not as expected)
Container as built: [3, 1, 2]
Container after first shift: [3, 1, 2]
Container after second shift: [3, 1, 2]如您所见,当我将修改操作放在与operator<<相同的行上时,输出似乎会缓冲更改(因为缺少更好的单词)。
我的问题是:
为什么会发生这种情况,以及如何使“同一行”行为与“逐行行为”相匹配。
谢谢!
编辑:
根据@KeithSmith的建议,我将Container::shift修改为:
Container& shift() {
std::cout<<"shifting... "<<std::flush;
int tmp = m_data[0];
m_data[0] = m_data[1];
m_data[1] = m_data[2];
m_data[2] = tmp;
return *this;
}得到了输出:
Behaviour Line-By-Line (works as expected)
Container as built: [1, 2, 3]
shifting... Container after first shift: [2, 3, 1]
shifting... Container after second shift: [3, 1, 2]
Behaviour On The Same Line (not as expected)
shifting... shifting... Container as built: [3, 1, 2]
Container after first shift: [3, 1, 2]
Container after second shift: [3, 1, 2]正如在几个答案中所解释的,操作的顺序没有定义。在“不像预期的”情况下,转移发生在流之前,但我想它可能以任何顺序发生。
我的带走:非常,非常小心,当inlining手术有副作用!我想我早该知道的!可惜我没有!
发布于 2013-12-09 22:05:48
第二个cout大致转换为operator <<(operator <<(operator <<(cout, c), c.shift(), c.shift()),并且由于参数计算顺序未指定,所有的转移都可以在开始时发生。
第一个;中的cout引入了序列点,这确保了评估顺序。有关序列点的更多信息,请参见这个:Undefined behavior and sequence points。
发布于 2013-12-09 22:06:50
未指定计算函数参数的顺序。如果表达式有副作用,并且取决于它们的顺序,则需要确保按顺序执行。也就是说,这些声明
std::cout<<"Container as built: "<<c<<std::endl
<<"Container after first shift: "<<c.shift()<<std::endl
<<"Container after second shift: "<<c.shift()<<std::endl;可以处理为
c.shift()c.shift()它还可以以不同的顺序计算表达式。只对shift操作符的函数调用进行排序,显然,如果它依赖于子表达式,则需要首先计算子表达式。
https://stackoverflow.com/questions/20481729
复制相似问题