以下代码运行正常,但是当删除第9行cout.rdbuf(x);
时,发生段故障。
大家能告诉我原因吗?
我对C ++不熟悉...
但是我必须在流出后直接继续指向out.txt。
我的环境是Ubuntu 12。
非常感谢!
#include <iostream>
#include <fstream>
using namespace std;
int main(void)
{
ofstream outf("out.txt");
streambuf* x = cout.rdbuf(outf.rdbuf());// redirect to out.txt
cout << "Testn"<<endl; // write to out.txt
cout.rdbuf(x); // recovery
cout << "Test2n"<<endl; // write to screen
return 0;
}
尽管所有内容都打印到out.txt中,但以下代码中发生了段错误。
#include <iostream>
#include <fstream>
using namespace std;
int main(void)
{
ofstream outf("out.txt");
streambuf* x = cout.rdbuf(outf.rdbuf());// redirect to out.txt
cout << "Testn"<<endl; // write to out.txt
// cout.rdbuf(x); // recovery
cout << "Test2n"<<endl;
cout << "Test3n"<<endl;
cout << "Test4n"<<endl;
cout << "Test5n"<<endl;
//Test2n~Test5n is printed to out.txt, but segment fault occurs now.
return 0;
}
答案 0 :(得分:0)
(如您所确定的),此问题是由于两个输出流共享一个缓冲区而关闭而导致的。我们可以通过编译代码并在Valgrind中运行它来看到这一点:
$ g++ -g -Wall -Wextra 52079058.cpp -o 52079058
$ valgrind -q --leak-check=full ./52079058
==27111== Invalid read of size 8
==27111== at 0x4985EC8: pubsync (streambuf:278)
==27111== by 0x4985EC8: std::ostream::flush() (ostream.tcc:219)
==27111== by 0x491C0EB: std::ios_base::Init::~Init() (ios_init.cc:134)
==27111== by 0x4BE28F0: __run_exit_handlers (exit.c:108)
==27111== by 0x4BE29E9: exit (exit.c:139)
==27111== by 0x4BCCB1D: (below main) (libc-start.c:344)
在这里,我们可以看到一个流正在尝试刷新到另一个流已删除的缓冲区。因此,在此之前,我们始终需要确保每个缓冲区完全由一个流拥有。
如果您需要确保std::cout
的缓冲区已恢复,而不管其代码路径如何,那么您可能想创建一个基于范围的保护对象,该对象在被销毁后将恢复。
类似这样的东西:
#include <iostream>
#include <fstream>
class stream_redirection
{
std::ostream& from;
std::ofstream to;
std::streambuf *const saved;
public:
stream_redirection(std::ostream& from, const std::string& filename)
: from{from},
to{filename},
saved{from.rdbuf(to.rdbuf())}
{}
stream_redirection(const stream_redirection&) = delete;
void operator=(const stream_redirection&) = delete;
~stream_redirection()
{
from.rdbuf(saved);
}
};
int main()
{
{
auto guard = stream_redirection(std::cout, "out.txt");
std::cout << "Testn"<<std::endl; // write to out.txt
std::cout << "Test2n"<<std::endl;
std::cout << "Test3n"<<std::endl;
}
std::cout << "Test4n"<<std::endl; // write to screen
std::cout << "Test5n"<<std::endl;
}
如果直接在guard
中创建main()
,而不是在内部作用域(如我在此处演示的那样)中创建main()
,那么重定向将在程序退出时清除(即,当{ {1}}返回)。
我认为必须创建这样的类表明程序中某处存在严重的设计缺陷。任何需要产生输出的子系统都应该传递一个写入该输出的流(有些子系统会走得更远,并认为日志记录和错误流也应该在需要的地方传递)。