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.
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:What you want is this: