是否有必要重置cout,cerr和clog的rdbuf,如果它们已被更改为重定向到文件?

时间:2015-11-09 03:03:54

标签: c++ g++

在尝试找出如何回答https://stackoverflow.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;
}

通过此更改,程序运行没有任何问题。

我使用cerrclog进行了类似的实验,结果相同。

这引出了我的问题:

是否始终需要重置rdbuf coutcerrclog,如果它们已被更改为重定向到文件?

如果没有,这是一个g ++缺陷吗?

1 个答案:

答案 0 :(得分:6)

引自Nicolai Josuttis的The C++ Standard Library - A tutorial and reference第2版,

章。 15.12.13,重定向标准流第822页

  

...

     

std::cout.rdbuf (file.rdbuf());

     

小心!对象file是本地的,在块的末尾会被销毁。这也会破坏相应的流缓冲区。这与“普通”流不同,因为文件流在构造时分配它们的流缓冲区对象并在销毁时销毁它们。因此,在此示例中,cout不能再用于写入。事实上,它甚至无法在程序终止时安全销毁。因此,应始终保存旧缓冲区并在以后恢复!

所以答案似乎是肯定的,即使我没有标准报价,上面的作者也是一位专家。