2011-01-20 116 views
20

我需要一个类,在其对象的生命周期中将一个ostream重定向到另一个ostream。经过一番修补后,我想出了这个:重定向std :: cout

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

它似乎工作正常。然而,它的怪异的是,下面一行是构造函数和析构函数重复:

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

我认为这是正确的,但我想验证与SO社区。你能在这段代码中发现任何错误或危险吗?

编辑

使不可复制。

+4

+1 - 这应该是正确的 - 但它会更好,如果你在一个通用的术语来实现你的逻辑`std :: ostream`而不是直接调用`std :: cout`。 – 2011-01-20 22:06:34

+1

@Billy ONeal:ScopedRedirect是不是已经用通用的ostream实现了? std :: cout仅用于示例中。 – StackedCrooked 2011-01-20 22:11:03

回答

17

这些行是相同的原因是因为你在做什么是交换缓冲区。 (也就是说,通过将原始缓冲区与重定向缓冲区交换来“重定向”;恢复是交换回)。

虽然这可能会给您输出流的预期效果,但它不正确,因为重定向流现在输出到别的地方。至重定向表示取一个数据流并将其输出到其他地方;注意这并不影响'别的地方'。

您的课程不是重定向;因为它应该真的被命名为ScopedStreamSwap。例如,试试这个来代替:

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

你想要的是这样的:

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