c++ - 返回对此的引用时出现意外的 std::ostream 输出

标签 c++ c++11 ostream

我肯定是遗漏了一些非常基本的东西。

我有一个简单的类,我在其中执行“就地”操作,然后返回对 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/

相关文章:

c++ - 从 Windows API 获取计算机的域名

c++ - 接收任何标准 map 的功能模板

C++11 gcc 4.9.2 算法 partition_copy() 导致 SIGABRT,与 back_inserter 一起工作

c++ - 输出到多个 ostream(文件和控制台)的类

c++ - istream >> ostream << 使用 * 指针重载运算符

c++ - Qt 嵌套模型 View

c++ - 返回模板

c++ - 带有 Github 的 Visual Studio 文件夹

c++ - 为什么 std::initializer_list 不支持 std::get<>、std::tuple_size 和 std::tuple_element

C++运算符重载无法输出+运算