cout、cerr、clog的rdbuf如果改成重定向到文件,是不是需要重新设置?
Posted
技术标签:
【中文标题】cout、cerr、clog的rdbuf如果改成重定向到文件,是不是需要重新设置?【英文标题】:Is it necessary to reset rdbuf of cout, cerr, and clog if they have been changed to be redirected to a file?cout、cerr、clog的rdbuf如果改成重定向到文件,是否需要重新设置? 【发布时间】:2015-11-09 03:03:54 【问题描述】:在试图弄清楚如何回答 https://***.com/questions/33601384/what-is-the-file-descriptor-of-linuxs-environments-standard-logging-stream 时,我注意到了一个指向 an answer to a related SO post 的链接。我使用 g++ 4.8.4 尝试了上述链接答案中的代码,并在程序终止之前出现分段错误。
这是程序:
#include <iostream>
#include <fstream>
int main()
std::ofstream of("cout.txt");
std::cout.rdbuf(of.rdbuf());
std::cout << "test. test. test." << std::endl;
return 0;
构建程序的命令:
g++ -Wall -std=c++11 -g socc.cc -o socc
gdb
的输出:
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from socc...done.
(gdb) run
Starting program: /.........../socc (removed some text here)
Traceback (most recent call last):
File "/usr/share/gdb/auto-load/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19-gdb.py", line 63, in <module>
from libstdcxx.v6.printers import register_libstdcxx_printers
ImportError: No module named 'libstdcxx'
Program received signal SIGSEGV, Segmentation fault.
0x000000000040073c in ?? ()
(gdb) bt
#0 0x000000000040073c in ?? ()
#1 0x0000000000000000 in ?? ()
(gdb)
我更新了程序以保留旧的 rdbuf
和 cout
,并在程序结束前将其重置。
#include <iostream>
#include <fstream>
int main()
std::ofstream of("cout.txt");
auto cout_buff = std::cout.rdbuf();
std::cout.rdbuf(of.rdbuf());
std::cout << "test. test. test." << std::endl;
std::cout.rdbuf(cout_buff);
return 0;
通过此更改,程序运行没有任何问题。
我对@987654330@ 和clog
进行了类似的实验,结果相同。
这引出了我的问题:
如果 cout
、cerr
和 clog
已更改为重定向到文件,是否始终需要重置 rdbuf
?
如果不是,这是 g++ 缺陷吗?
【问题讨论】:
【参考方案1】:引用The C++ Standard Library - A tutorial and reference Nicolai Josuttis 的第二版,
Ch. 15.12.13,重定向标准流 pp. 822
...
std::cout.rdbuf (file.rdbuf());
注意! 对象
file
是本地的,在块的末尾被销毁。这也会破坏相应的流缓冲区。这与“正常”流不同,因为文件流在构建时分配其流缓冲区对象并在销毁时销毁它们。因此,在此示例中,cout
不能再用于写入。事实上,它甚至不能在程序终止时安全地销毁。因此,应始终保存旧缓冲区并在以后恢复!
所以答案似乎是肯定的,尽管我没有标准的报价,但上面的作者是相当专家。
【讨论】:
很好的发现。谢谢。 你不一定需要换回来;问题是basic_filebuf
的生命周期,如果您不将缓冲区更改为其他内容,它必须比cout
更持久。例如,您可以在末尾执行std::cout.rdbuf(nullptr);
,而不是保存和恢复原始缓冲区。
我从标准中注意到:~ios_base():析构函数不会破坏rdbuf()。看起来像 ~basic_fstream()
或 ~basic_ofstream()
破坏相应的 rdbuf()
。
@T.C.确实如此,否则析构函数可能会尝试双重删除。
@vsoftco 不,basic_ios
和 basic_ostream
的析构函数都没有触及 rdbuf()
。这里的问题是ios_base::Init::~Init()
刷新了流,如果流缓冲区消失了,这显然是不好的。以上是关于cout、cerr、clog的rdbuf如果改成重定向到文件,是不是需要重新设置?的主要内容,如果未能解决你的问题,请参考以下文章