2016-02-23 17 views
5

sto saltando dalla C in C++ con l'aiuto del libro C++ Primer (5a edizione), dove l'autore afferma quanto segue:Dovrebbe essere sempre usato std :: endl?

programmatori spesso aggiungono istruzioni print durante il debug. Tali istruzioni devono sempre svuotare il flusso. Altrimenti, se il programma si arresta in modo anomalo, è possibile che l'output rimanga nel buffer, portando a inferenze errate di su dove si è verificato il crash del programma.

Ma i post online suggeriscono diversamente; alcuni dicono che lo svuotamento costante del buffer fa male al programma e causa problemi di prestazioni.

Le mie domande:

  1. Quando si dovrebbe utilizzare std::endl?
  2. L'autore ha torto o ho frainteso qualsiasi parte di ciò che ha dichiarato?
  3. È possibile fornire scenari reali in cui è necessario eseguire il flushing del flusso di output?

P.S.

  1. Cosa significa flushing del buffer?
+9

Perché ti interessano le prestazioni delle istruzioni che vengono eseguite solo durante il debug? – rightfold

+0

La risposta al n. 3 è proprio lì in quello che hai citato: "se il programma si blocca, l'output potrebbe essere lasciato nel buffer, portando a inferenze errate su dove il programma si è bloccato". – interjay

+4

Si noti che il modo più semplice per svuotare è usare 'std :: cerr' per iniziare. –

risposta

2

punto 4 e il punto 3

partire con il punto 4 perché tutto il resto dipende su di esso e al punto 3 perché è strettamente correlato.

Quando si scarica lo stream, si stanno prendendo tutti i dati memorizzati dallo stream e lo si scrive sul supporto sottostante rappresentato dallo stream.

Quando viene svuotato, è fatto, impegnato e pronto per essere osservato dal mondo esterno (Più o meno Il sistema operativo e l'hardware che supporta il flusso può anche ritardare la scrittura, ma non c'è molto che tu possa fare per quello). Non puoi leggerlo finché non è stato lavato. Se non viene mai scaricato, non puoi leggerlo.

La cosa è che non si vuole scrivere su IO molto spesso perché tutto ciò che esce dalla CPU impiega una quantità di tempo non voluta rispetto a quello che rimane all'interno della CPU. A volte decine di migliaia di volte più lento. All'interno della CPU si hanno gigahertz e bus paralleli che spostano i dati 32 o più bit alla volta. All'esterno hai megahertz che si muove spesso un solo bit alla volta.

Prendere un file come un esempio classico. Non solo è l'accesso di unità in esecuzione a una frazione di una velocità della CPU, ma se ogni byte va direttamente su un disco, quindi per ogni byte potrebbe essere necessario

  1. trovare analogico che di byte sul disco.
  2. carica il settore attorno a quel byte in memoria. Quindi, invece di spostare un byte, potresti spostarti di alcune centinaia o di migliaia. Di solito 512 byte o 4096 byte.
  3. scrivere il byte nel settore in memoria
  4. scrivere settore in memoria indietro sul disco

brutale. Immagina di farlo alcune centinaia o migliaia di volte per scrivere una singola stringa. Ma cosa succede se hai scritto la stringa solo quando è diventata troppo grande da tenere o hai finito? Cosa succede se hai scritto in settori piuttosto che in byte? Quindi è possibile

  1. trovare il settore dell'analogo del byte sul disco.
  2. scrivere settore memorizzato sul disco

Un'operazione per potenzialmente migliaia di byte in un colpo.

Point 2

punto 2 torna al punto quattro/tre di non si può leggere ciò che non lo fanno a filo. Se vuoi vedere un particolare output sullo schermo e vuoi vederlo ora, lo svuoti. Se si desidera ottenere un messaggio di debug prima che il programma si blocchi, e probabilmente si interrompe senza ottenere quegli ultimi pochi messaggi assolutamente essenziali sullo schermo, si scarica. La cronologia è piena di programmatori che cercano nel posto sbagliato un errore perché non hanno ricevuto quegli ultimi messaggi di errore non aggiornati.

Stai scambiando la velocità del programma per la relativa certezza che vedrai un messaggio importante quando devi vederlo.

punto 1

punto 1 chiamate al punto 2. std::endl è sia un'estremità di linea e un'istruzione per irrigare il flusso. Lo usi con parsimonia e solo quando hai bisogno sia di un fine linea che di un colore. Se non hai bisogno di un colore, invia e termina la riga: '\n'.

Prendere il consiglio di Pete Becker e utilizzare std::cerr per errori e debug, ove possibile. Questo è quello per cui è stato costruito. Funziona con la forza bruta e l'ignoranza. È doloroso. È lento. E funziona quasi sempre.

+0

qual è il "supporto sottostante" nello stream? –

+0

Dipende dallo stream. Un 'fstream' rappresenta un file come supporto sottostante. 'cin' e' cout' siedono in cima a una console, e quella console può leggere o scrivere praticamente su qualsiasi cosa, ma di solito lo schermo, una porta seriale o una presa di rete. Il mezzo di 'stringstream' è un blocco di memoria. – user4581301

1

Sia l'autore che i post hanno ragione.

stream << std::endl è in realtà stream << '\n' << std::flush. Lo svuotamento esplicito presenta svantaggi in termini di prestazioni ed è per questo motivo che non dovresti utilizzarlo in situazioni critiche dal punto di vista delle prestazioni. Raramente si pensa a problemi di prestazioni così trascurabili durante il debug, quindi attualmente lo è una buona pratica per svuotare esplicitamente l'output di debug.

0

Per default std::cout è legata alla stdout, che è ...

fully-buffered se e solo se il flusso non può essere determinato per riferirsi ad un dispositivo interattivo.

(C99, 7.19.3 Files, punto 7)

Ciò significa che, se l'output viene inviato al terminale, std::endl vs. "\n" non fa differenza, in primo luogo. ;-)


quanto riguarda la tua domanda effettiva:

entrambi è vero:

  • buffer di uscita unflushed possono portare a conclusioni errate circa in cui il programma è schiantato
  • vampate di i buffer di output influiscono sulle prestazioni

Questo diventa un problema solo dopo aver aggiunto "sempre".

Quando si deve usare std::endl?

Quando si si desidera svuotare il buffer.

L'autore ha sbagliato o mi è mancato di comprendere qualsiasi parte di ciò che ha dichiarato?

Penso quantificatori assoluti come "sempre", "tutti", "mai", ecc dovrebbe essere preso con un grano di sale, per quanto di stile/disegno/ecc è interessato.

(eccezione: Mai invocare un comportamento indefinito ;-).)

Puoi dare alcuna scenari del mondo reale per reale necessità di scarico del flusso di uscita?

Ogni volta che non avendo la ultima uscita in realtà sembrano non sarebbe accettabile. Se questo è il caso in ogni dato scenario è un giudizio.

Personalmente, vorrei prendere in considerazione i registri di produzione/transazioni ad essere più critico rispetto registri di debug ...

0

1) Quando si dovrebbe utilizzare std :: endl?

Quando si desidera essere sicuri che il buffer venga immediatamente svuotato.

2) L'autore ha sbagliato o mi è mancato di comprendere qualsiasi parte di ciò che ha dichiarato ?

No, l'autore è corretto, e anche tu.

3) è possibile fornire scenari reali per l'effettiva necessità di flusso flusso di uscita?

Quando una stringa particual viene scritto i lotti flusso di volte in un breve lasso di tempo std::endl potrebbe infatti causare la perdita di prestazioni a causa del flussaggio inutile del buffer ogni volta. Tuttavia, quando si tratta di stampare linee che vengono aggiunte per il solo scopo del debug, si dovrebbe sempre svuotare il buffer. Poi di nuovo, se stai eseguendo il debug di un'applicazione con solo linee di stampa senza usare un debugger, stai facendo qualcosa di sbagliato in primo luogo.

-7

Non utilizzare mai std::endl. Questo è un culto del carico che deve svanire. Non ti dà altro che svantaggio delle prestazioni. Basta fare una memoria muscolare: sempre "\n", mai std::endl.

+0

Downvote tutto quello che vuoi, questa è la mia posizione a lungo termine. A proposito, anche la registrazione sincrona deve essere abolita. – SergeyA

+3

"mai" è nella stessa lega di "sempre": non mi piacciono le affermazioni assolute in contesti come questi, fanno più danni che buoni. Non è il mio downvote, ma hai già la tua parte. ;-) – DevSolar

+0

@DevSolar, che ne dici di "non si dovrebbero mai usare puntatori proprietari"? A volte non significa mai mai. – SergeyA

7

L'output di debug deve essere scritto su std::cerr; è unità bufferizzata, quindi ogni personaggio viene lavato. Raramente c'è bisogno di std::endl, e abituarsi ad usarlo porterà ad un codice misteriosamente lento. Basta usare '\n' a meno che non si sappia che è necessario svuotare il buffer.

Problemi correlati