2016-06-01 47 views
13

Nel tentativo di comprendere meglio i flussi bufferizzati in C++, vorrei scrivere un semplice programma in cui il buffer std::cout NON viene svuotato prima della conclusione. Da quando ho letto che std::cout viene svuotato alla chiusura normale, ho provato a lanciare un errore di runtime. Ho anche evitato di usare std::endl, poiché capisco che impone un flush. Primo tentativo:Come creare un semplice programma C++ in cui std :: cout non viene svuotato

//file noflush.cpp 
#include <iostream> 

int main() { 
    std::cout << "Don't write me to the console!"; 
    throw 0; 
} 

compilazione con g ++, chiamata dal terminale:

$ ./noflush 
libc++abi.dylib: terminating with uncaught exception of type int 
Don't write me to the console!Abort trap: 6 

Anche quando forzo un errore di runtime, sembra che il tampone viene ancora lavata al termine. È possibile "filare" alcuni dati nel buffer, lasciandolo non scritto sul dispositivo?

+0

Solo per dire che anche quando abortire con 'std :: Abort()' il buffer si svuota, (utilizzando Apple LLVM versione 6.0 (clang-600.0.57) (basato su LLVM 3.5svn) con LLVM libC++), sebbene accor ding to [cppreference] (http: //en.cppreference.com/w/cpp/utility/program/abort) è l'implementazione definita * se le risorse aperte come i file sono chiuse * (alla chiamata 'std :: abort()'). – Walter

risposta

10

Questo non è C++ standard, ma in POSIX, è possibile inviare un segnale "kill" per interrompere il processo in esecuzione. Ciò interromperà l'esecuzione senza pulizia come i buffer di scarico.

Modifica: mi sono reso conto che i segnali non sono solo POSIX ma in realtà parte della libreria standard C (e inclusi nella libreria standard C++).

#include <csignal> 
// ... 
std::cout << "Don't write me to the console!"; 
std::raise(SIGKILL); 
+0

Che ne dici di puntatore nullo di dereferenziazione per indurre l'eccezione puntatore nullo/runtime seg faul ? Potrebbe essere un buon modo multipiattaforma per uccidere un processo. – kevinarpe

+0

@kevinarpe il dereferenziamento di un puntatore nullo ha un comportamento non definito, quindi non è garantito il kill del processo e non è tecnicamente portabile ... In pratica però, * il crash su un puntatore nullo di dereferenziazione * potrebbe essere più ampiamente "supportato" rispetto a POSIX. Questo è fondamentalmente lo stesso suggerimento della risposta di Caduchon, ad eccezione dell'UB da una dereferenziazione del puntatore nullo probabilmente più coerente di UB dal dereferenziazione e dall'eliminazione di un puntatore non inizializzato. – user2079303

+1

@kevinarpe Lo schianto sul dereferenziamento di un puntatore nullo non è garantito. – Leandros

4

con il seguente esempio, posso creare il comportamento che si desidera con gcc 4.8.3:

#include <iostream> 
#include <vector> 

int main() 
{ 
    std::string str; 
    for(unsigned long int i = 0; i < 10000; ++i) 
     str += "Hello ! "; 
    str += "END"; 
    std::cout << str; 

    std::vector<double>* p; 
    p->push_back(1.0); 
    delete p; 

    std::cout << "STILL ALIVE !" << std::endl; 

    return 0; 
} 

Poi, l'output è:

Ciao! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! Ciao ! [...] Ciao ! Difetto di segmentazione

Si può vedere che END non viene stampato prima dell'errore di segmentazione.

+0

Uhmm ... l'esempio funziona anche con 10 anziché 10000 nel ciclo? –

+1

Quando ho provato con 10, l'errore di segmentazione era immediato. Quindi sì, funziona anche, ma più sfocato. – Caduchon

+0

il codice iniziale NON mostra il comportamento che l'OP sta cercando, perché il programma si blocca anche prima di mettere "ANCORA VIVO!" nel buffer, mentre con 10 anziché 10000 si blocca senza visualizzare nulla, mentre l'Hello! ARE nel buffer: questo è il bahaviour atteso – Guiroux

9

Per quanto posso dire, non c'è modo conforme e pulito di serie per evitare std::cout a flush() prima della cessazione del programma (ma, naturalmente, è possibile utilizzare i metodi sporchi, ad esempio sollevando un segnale sia directly o indirectly). Secondo cppreference, il tipo di buffer effettivo controllato da std::cout è definito dall'implementazione ma derivato da std::streambuf, che non sembra consentire l'accesso pubblico in un modo che possa emulare la deglutizione silenziosa del buffer.

Inoltre, come ho osservato in un commento, anche la terminazione anomala del programma (tramite std::terminate() o std::abort() può o non può chiudere le risorse aperte, quindi questo è ancora implementazione definita.

+0

La citazione corretta è "L'oggetto globale std :: cout [...] restituisce l'output su un buffer di flusso di tipo definito dall'implementazione [...]" (Il buffer e non l'oggetto flusso è definito dall'implementazione) –

+0

@ DieterLücking Grazie. Ho modificato il testo. – Walter

0

Se ho ragione, si vuole la cattura o ignorare l'output std::cout:

#include <iostream> 
#include <sstream> 
int main() 
{ 
    // Capture the output to `std::cout` 
    { 
     std::cout << "[Capture Output]" << std::endl; 
     std::stringstream cpature; 
     auto restore = std::cout.rdbuf(cpature.rdbuf()); 

     std::cout << "... captured output ..." << std::endl; 

     std::cout.rdbuf(restore); 
     std::cout << "[Enable Output]" << std::endl; 

     // Display the cpatured output. 
     std::cout << cpature.rdbuf(); 
    } 
    std::cout << std::endl; 

    // Even more drasticly: Ignore the output to `std::cout` 
    { 
     std::cout << "[Ignore Output]" << std::endl; 
     auto restore = std::cout.rdbuf(nullptr); 

     std::cout << "... ignored output ..." << std::endl; 

     std::cout.rdbuf(restore); 
     std::cout << "[Enable Output]" << std::endl; 
    } 

    std::cout << "[End]\n"; 
} 
0
#include <iostream> 
#include <sstream> 
#include <vector> 
int main() 
{ 
    std::stringstream cpature; 
    auto restore = std::cout.rdbuf(cpature.rdbuf());  
    std::cout.rdbuf(restore); 
    for(unsigned long int i = 0; i < 10000; ++i) 
     std::cout <<"Hello ! " << std::endl; 
    std::cout << "END" << std::endl; 

    std::cout << cpature.rdbuf(); 
    std::vector<double> *p; 
    p->push_back(1.0); 
    delete p; 
    std::cout << "STILL ALIVE !" << std::endl; 
}