Joh*_*ane 6 c++ fstream streambuf undefined-behavior
作者在标题下提出了这段代码A bus error on my platform
#include <fstream>
#include <iostream>
int main()
{
std::ofstream log("oops.log");
std::cout.rdbuf(log.rdbuf());
std::cout << "Oops!\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
字符串"Oops!\n"将打印到文件"oops.log".代码不会恢复cout的streambuf,但VS2010没有报告运行时错误.
由于log并std::cout共享一个缓冲区,该缓冲区可能会被释放两次(一旦log超出范围,则在程序终止时再次释放).
这会导致未定义的行为,因此很难说出它在机器上触发总线错误的确切原因,但是在您的机器上无声地失败.
由于其他答案没有提到如何解决这个问题,我将在这里提供。您需要保存和恢复 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;
}
Run Code Online (Sandbox Code Playgroud)
现在,当cout的缓冲区cout在程序结束时被销毁之前被替换时,因此当cout销毁其缓冲区时,正确的事情就会发生。
对于简单地重定向标准 io,通常环境已经能够为您做到这一点(例如,shell 中的 io 重定向)。而不是上面的代码,我可能只是简单地将程序运行为:
yourprogram > oops.log
Run Code Online (Sandbox Code Playgroud)
还有一件事要记住,这std::cout是一个全局变量,与其他全局变量具有相同的缺点。您可能更喜欢使用通常的技术来避免全局变量,而不是修改它甚至使用它。例如,您可以传递一个std::ostream &log_output参数并使用它,而不是cout直接使用代码。
| 归档时间: |
|
| 查看次数: |
962 次 |
| 最近记录: |