2011-01-20 113 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; 
}