我肯定是遗漏了一些非常基本的东西。
我有一个简单的类,我在其中执行“就地”操作,然后返回对 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 X 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
时要非常非常小心有副作用的手术!我想我应该知道这个!遗憾的是我没有!
最佳答案
未指定计算函数参数的顺序。如果你的表达式有副作用并且你依赖于它们的顺序,你需要确保你按顺序执行事情。也就是说,语句
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()
- 现在它已评估所有对象并开始输出它们。
它也可以以不同的顺序评估表达式。只有移位运算符的函数调用是有序的,显然,在它依赖于子表达式的地方,子表达式需要首先求值。
关于c++ - 返回对此的引用时出现意外的 std::ostream 输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20481729/