2011-01-20 21 views
20

मुझे एक ऐसी कक्षा की आवश्यकता है जो एक ऑस्ट्रीम को अपने ऑब्जेक्ट के जीवनकाल के दौरान एक अन्य ओस्ट्रीम पर रीडायरेक्ट करे। कुछ tinkering के बाद मैं इसके साथ आया:रीडायरेक्टिंग 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())); 

मुझे लगता है कि यह सही है, लेकिन मैं इतना समुदाय के साथ सत्यापित करने के लिए करना चाहते हैं। क्या आपको इस कोड में कोई त्रुटि या खतरे मिल सकती हैं?

संपादित करें

गैर-प्रतिलिपि बनाएं।

+4

+1 - यह सही होना चाहिए - लेकिन यह अच्छा होगा यदि आप एक सामान्य के संदर्भ में अपने तर्क लागू किया 'std :: cout' को सीधे कॉल करने के बजाय' std :: ostream'। –

+1

@ बिली ओनेल: क्या स्कोप्ड रेडियोधर्मी पहले से ही एक सामान्य ओस्ट्रीम के संदर्भ में लागू नहीं किया गया है? Std :: cout केवल नमूना में प्रयोग किया जाता है। – StackedCrooked

+0

मैं नहीं कह रहा हूं कि आपकी कक्षा खराब है या गलत है। मैं बस इतना कह रहा हूं कि आउटपुट भेजने के लिए बेहतर होगा जहां आप वास्तव में रीडायरेक्ट करने के लिए कहां जाना चाहते हैं, यह तथ्य के बाद कहां जा रहा है। यही है, मैं कोड कह रहा हूं जो कि किसी भी विशेष स्थान पर इंगित std :: cout पर निर्भर करता है, जहां कोउट पॉइंट्स बदलने के बजाए refactored किया जाना चाहिए। –

उत्तर

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; 
} 
+2

+1 दिलचस्प और जानकारीपूर्ण, और उल्लसित उदाहरण पाठ के लिए +1। –

+0

एक कामकाजी फिक्स पोस्ट करने के लिए धन्यवाद। मुझे एहसास हुआ था कि मैं बस बफर को स्वैप कर रहा था, लेकिन मैं अजीब तरह से इसे अलग करने में असमर्थ था। किसी कारण से वाक्यविन्यास मुझे बहुत भ्रमित करता है। – StackedCrooked

संबंधित मुद्दे