gpt4 book ai didi

c++ - 为什么将流外重定向到文件时会出现段错误?

转载 作者:太空宇宙 更新时间:2023-11-04 12:45:05 24 4
gpt4 key购买 nike

以下代码运行正常,但是当第 9 行 cout.rdbuf(x); 被删除时,出现段错误。大家能告诉我原因吗?我对C++不熟悉...但是在outstream指向out.txt之后我必须不断地cout。我的环境是 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;
}

最佳答案

问题是(正如您所确定的)允许关闭两个输出流,同时它们共享一个缓冲区。我们可以通过编译代码并在 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;
}

如果您直接在 main() 中创建 guard,而不是像我在这里演示切换那样在内部作用域中创建,那么重定向将被清除在程序退出时向上(即当 main() 返回时)。


我认为必须创建这样一个类表明您的程序中某处存在严重的设计缺陷。任何需要产生输出的子系统都应该传递一个流来写入输出(有些人会更进一步,并认为日志记录和错误流也应该在需要的地方传递)。

关于c++ - 为什么将流外重定向到文件时会出现段错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52079058/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com