C++ 如果cout.rdbuf()用于切换缓冲区而从不将其设置回原位,会出现什么问题?

C++ 如果cout.rdbuf()用于切换缓冲区而从不将其设置回原位,会出现什么问题?,c++,fstream,undefined-behavior,streambuf,C++,Fstream,Undefined Behavior,Streambuf,作者在标题为《我的平台上的总线错误》下发表 #include <fstream> #include <iostream> int main() { std::ofstream log("oops.log"); std::cout.rdbuf(log.rdbuf()); std::cout << "Oops!\n"; return 0; } #包括 #包括 int main() { std::流日志(“oops.log”);

作者在标题为《我的平台上的总线错误》下发表

#include <fstream>
#include <iostream>

int main()
{
    std::ofstream log("oops.log");
    std::cout.rdbuf(log.rdbuf());
    std::cout << "Oops!\n";
    return 0;
}
#包括
#包括
int main()
{
std::流日志(“oops.log”);
std::cout.rdbuf(log.rdbuf());

std::cout由于
log
std::cout
共享一个缓冲区,该缓冲区可能会被释放两次(当
log
超出范围时释放一次,当程序终止时释放一次)


这会导致未定义的行为,因此很难说出它在他的计算机上触发总线错误但在您的计算机上自动失败的确切原因。

您的程序具有未定义的行为

全局
cout
对象的析构函数将在超出范围时删除流缓冲区,而
log
也是如此,它也拥有相同的流缓冲区。因此,您将删除相同的对象两次

当一个程序有未定义的行为时,任何事情都有可能发生,从格式化硬盘到终止而没有任何错误


例如,在我的平台上,程序从
main()

返回后进入一个无限循环,因为其他答案没有提到如何处理这个问题,我将在这里提供。您需要保存和恢复cout应该管理的缓冲区。例如:

#include <fstream>
#include <iostream>

// RAII method of restoring a buffer
struct buffer_restorer {
    std::ios &m_s;
    std::streambuf *m_buf;

    buffer_restorer(std::ios &s, std::streambuf *buf) : m_s(s), m_buf(buf) {}
    ~buffer_restorer() { m_s.rdbuf(m_buf); }
};

int main()
{
    std::ofstream log("oops.log");
    buffer_restorer r(std::cout, std::cout.rdbuf(log.rdbuf()));
    std::cout << "Oops!\n";
    return 0;
}

还有一点需要记住的是,
std::cout
是一个全局变量,与其他全局变量具有相同的缺点。与其修改它,甚至使用它,您可能更喜欢使用通常的技术来避免所有全局变量。例如,您可以传递一个
std::ostream&log_输出
参数使用它,而不是让代码直接使用
cout

有什么办法解决这个问题吗?@Caesar,是的,一开始就不共享流缓冲区。我想知道原作者试图通过这样做实现什么。你应该详细说明你的标题。
yourprogram > oops.log