2011-01-20 8 views
20

Ho bisogno di una classe che reindirizzi un ostream a un altro ostream durante la vita del suo oggetto. Dopo un po 'di ritmi, ho inventato questo:Reindirizzamento 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; 
} 

Sembra funzionare bene. Tuttavia, è strano che la seguente riga si ripete in sia il costruttore e distruttore:

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

Penso che sia corretto, ma vorrei verificare con il SO comunità. Riesci a trovare errori o pericoli in questo codice?

Modifica

Rendi non copiabile.

+4

+1 - Dovrebbe essere corretto - ma sarebbe meglio se si implementato la logica in termini di una generica 'std :: ostream' piuttosto che chiamare' std :: cout' direttamente. –

+1

@Billy ONeal: Is scopedRedirect non è già implementato in termini di ostream generico? Il codice std :: cout è utilizzato solo nel campione. – StackedCrooked

+0

Non sto dicendo che la tua classe sia cattiva o scorretta. Sto solo dicendo che sarebbe meglio inviare l'output a dove vuoi che vada effettivamente piuttosto che reindirizzare dove sta andando dopo il fatto. Cioè, sto dicendo che il codice che si basa su std :: cout che punta a una particolare posizione dovrebbe essere refactored piuttosto che cambiare i punti cout. –

risposta

17

Il motivo per cui le linee sono le stesse è perché quello che stai facendo è lo scambiare i buffer. (Ovvero, si "reindirizza" scambiando il buffer originale con il buffer di reindirizzamento, il ripristino è lo swap back.)

Mentre questo potrebbe darti l'effetto desiderato rispetto al flusso di output, non è corretto perché il reindirizzamento lo stream ora esce da qualche altra parte. Per reindirizzare significa prendere uno stream e farlo uscire da qualche altra parte; si noti che ciò non influisce su "altrove".

La tua classe non è un reindirizzamento; così come dovrebbe essere chiamato ScopedStreamSwap. Ad esempio, provare questo, invece:

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

quello che vuoi è questo:

#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 per essere interessante e informativo e per un esilarante testo di esempio. –

+0

Grazie per aver pubblicato una correzione funzionante. Mi ero reso conto che stavo semplicemente scambiando i respingenti, ma stranamente non ero in grado di farlo diversamente. Per qualche motivo la sintassi mi confonde molto. – StackedCrooked

Problemi correlati