Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirecting std::cout

Tags:

I need a class that redirects one ostream to another ostream during the lifetime of its object. After some tinkering I came up with this:

#include <iostream> #include <fstream>   class ScopedRedirect { public:     ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :         mOriginal(inOriginal),         mRedirect(inRedirect)     {         mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));     }      ~ScopedRedirect()     {         mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));     }      private:     ScopedRedirect(const ScopedRedirect&);     ScopedRedirect& operator=(const ScopedRedirect&);      std::ostream & mOriginal;     std::ostream & mRedirect; };   int main() {     std::cout << "Before redirect." << std::endl;     std::ofstream filestream("redirected.txt");     {         ScopedRedirect redirect(std::cout, filestream);         std::cout << "During redirect." << std::endl;     }     std::cout << "After redirect." << std::endl;      return 0; } 

It seems to work fine. However, it's weird that the following line is repeated in both the constructor and destructor:

mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf())); 

I think it's correct, but I would like to verify with the SO community. Can you find any errors or dangers in this code?

Edit

Make non-copyable.

like image 970
StackedCrooked Avatar asked Jan 20 '11 22:01

StackedCrooked


People also ask

Why is std :: cout not working?

There is no std::cout in C. In a windowing system, the std::cout may not be implemented because there are windows and the OS doesn't know which one of your windows to output to. never ever give cout NULL. it will stop to work.

How do you write to stdout to a file in C++?

I/O Redirection in C++ For Example, to redirect the stdout to say a textfile, we could write : freopen ("text_file. txt", "w", stdout);

What std :: cout means?

std::cout is used to output a value (cout = character output) std::cin is used to get an input value (cin = character input)

What type is std :: cout?

std::cout is an object of class ostream that represents the standard output stream oriented to narrow characters (of type char). It corresponds to the C stream stdout. The standard output stream is the default destination of characters determined by the environment.


1 Answers

The reason those lines are the same is because what you're doing is swapping the buffers. (That is, you "redirect" by swapping the original buffer with the redirect buffer; restoration is the swap back.)

While this might give you the intended effect with respect to the output stream, it's not correct because the redirect stream now outputs somewhere else. To redirect means to take one stream and make it output somewhere else; note this doesn't effect that 'somewhere else'.

Your class is not a redirect; as is, it should really be named ScopedStreamSwap. For example, try this instead:

#include <iostream> #include <fstream>  class ScopedRedirect { public:     ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :         mOriginal(inOriginal),         mRedirect(inRedirect)     {         mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));     }      ~ScopedRedirect()     {         mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));     }      private:     ScopedRedirect(const ScopedRedirect&);     ScopedRedirect& operator=(const ScopedRedirect&);      std::ostream & mOriginal;     std::ostream & mRedirect; };   int main() {     std::cout << "Before redirect." << std::endl;     std::ofstream filestream("redirected.txt");     {         ScopedRedirect redirect(std::cout, filestream);         std::cout << "During redirect." << std::endl;          // oops:         filestream << "also to the file, right?...nope" << std::endl;         filestream << "ah, why am i on the screen?!" << std::endl;     }     std::cout << "After redirect." << std::endl;      // in main, return 0 is implicit, if there is no return statement;     // helpful to keep in mind in snippets and short things } 

What you want is this:

#include <iostream> #include <fstream>  class ScopedRedirect { public:     ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :         mOriginal(inOriginal),         mOldBuffer(inOriginal.rdbuf(inRedirect.rdbuf()))     { }      ~ScopedRedirect()     {         mOriginal.rdbuf(mOldBuffer);     }      private:     ScopedRedirect(const ScopedRedirect&);     ScopedRedirect& operator=(const ScopedRedirect&);      std::ostream & mOriginal;     std::streambuf * mOldBuffer; };   int main() {     std::cout << "Before redirect." << std::endl;     std::ofstream filestream("redirected.txt");     {         ScopedRedirect redirect(std::cout, filestream);         std::cout << "During redirect." << std::endl;          // yay:         filestream << "also to the file, right?...yes" << std::endl;         filestream << "i am not on the screen" << std::endl;     }     std::cout << "After redirect." << std::endl;      return 0; } 
like image 118
GManNickG Avatar answered Sep 25 '22 02:09

GManNickG