Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it necessary to reset rdbuf of cout, cerr, and clog if they have been changed to be redirected to a file?

Tags:

c++

g++

While trying to figure out how to answer https://stackoverflow.com/questions/33601384/what-is-the-file-descriptor-of-linuxs-environments-standard-logging-stream, I noticed a link to an answer to a related SO post. I tried the code in the above linked answer with g++ 4.8.4 and got segmentation error before the program terminated.

Here's the program:

#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;
}

The command to build the program:

g++ -Wall -std=c++11  -g   socc.cc   -o socc

Output from 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) 

I updated the program to keep the old rdbuf of cout and reset it before the end of the program.

#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;
}

With this change, the program ran without any problem.

I experimented similarly with cerr and clog with identical results.

That leads me to the questions:

Is it always necessary to reset rdbuf of cout, cerr, and clog if they have been changed to be redirected to a file?

If not, is this a g++ defect?

like image 508
R Sahu Avatar asked Nov 09 '15 03:11

R Sahu


1 Answers

Citing from The C++ Standard Library - A tutorial and reference 2nd edition by Nicolai Josuttis,

Ch. 15.12.13, Redirecting Standard Streams pp. 822

...

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

Caution! The object file is local and is destroyed at the end of the block. This also destroys the corresponding stream buffer. This differs from the “normal” streams because file streams allocate their stream buffer objects at construction time and destroy them on destruction. Thus, in this example, cout can no longer be used for writing. In fact, it cannot even be destroyed safely at program termination. Thus, the old buffer should always be saved and restored later!

So the answer seems to be Yes, and even though I don't have a standard quote, the author above is quite an expert.

like image 50
vsoftco Avatar answered Sep 18 '22 01:09

vsoftco