2016-02-23 89 views
5

我在C跳進C++的書的幫助下C++入門(第5版),在這裏筆者狀態如下:應該使用std :: endl嗎?

程序員經常在調試過程中添加打印語句。這樣的 語句應該總是刷新流。否則,如果程序 崩潰,輸出可能會留在緩衝區中,從而導致關於程序崩潰的位置的錯誤 推斷。

但在線帖子建議不然;有些人說,不斷刷新緩衝區對程序不利,並導致性能問題。

我的問題:

  1. 當你應該使用std::endl
  2. 作者是錯誤的還是我誤解了他所說的任何部分?
  3. 您是否可以提供任何需要刷新輸出流的真實場景?

P.S.

  1. 沖洗緩衝區是什麼意思?
+9

爲什麼要關心只在調試期間執行的語句的性能? – rightfold

+0

#3的答案就在你所引用的內容中:「如果程序崩潰,輸出可能會留在緩衝區中,導致程序崩潰的錯誤推論。」 – interjay

+4

請注意,最簡單的方法是使用'std :: cerr'開頭。 –

回答

2

4點和3點

與第4點開始,因爲一切在它和3點鉸鏈,因爲它是緊密相關的。

當您刷新流時,您將獲取流存儲的所有數據並將其寫入由流表示的底層介質。

當它被刷新時,它被完成,提交併準備好被外界觀察(或多或少,支持流的操作系統和硬件也可能延遲寫入,但是沒有太多可以這樣做)。直到它被刷新後才能讀取它。如果它從未被刷新,則無法讀取它。

事情是你不想經常寫入IO,因爲任何從CPU中出來的東西都會比呆在CPU中的時間多得多。有時候會慢幾萬倍。在CPU內部,你有千兆赫茲的並行總線,每次移動數據32位或更多位。外面你有兆赫茲經常移動一點一次。

拿一個文件作爲一個典型的例子。不僅是驅動器訪問運行在CPU的速度的一小部分,但如果每一個字節直接到磁盤,然後爲每個字節你可能要

  1. 發現字節的磁盤上的模擬。
  2. 將該字節周圍的扇區加載到內存中。所以不是移動一個字節,而是移動數百或者數千個字節。通常爲512字節或4096字節。
  3. 以字節爲扇區存儲
  4. 編寫部門在內存中回磁盤

殘酷。想象一下這樣做幾百次或幾千次來寫一個字符串。但是,如果你只寫了字符串,當它太大或無法完成時呢?如果你用扇區而不是字節來寫?那麼你可以

  1. 找到該字節的模擬磁盤上的扇區。
  2. 存儲行業寫入磁盤

一個操作可能數千字節的一次性。

點2

2點回到第四點/三相的,你看不懂,你做什麼不平齊。如果你想在屏幕上看到一個特定的輸出,並且你想現在看到它,你需要刷新。如果你想在程序崩潰之前得到一個調試消息,並且很可能會終止而不會在屏幕上顯示最後幾條絕對必要的消息,你可以刷新。歷史充滿了程序員在錯誤的地方尋找錯誤的地方,因爲他們沒有得到最後幾個未刷新的錯誤消息。

您正在交易程序速度的相對確定性,您將在需要查看時看到一條重要消息。

點1

點1呼叫回點2 std::endl既是線的端部和沖洗流的指令。只有在需要線尾和沖水時,纔會謹慎使用它。如果您不需要衝洗,只需發送和結束行:'\n'

以皮特貝克爾的建議,並使用std::cerr錯誤和儘可能調試。這就是它的目的。它運作蠻力和無知。這是痛苦的。這很慢。它幾乎總是有效的。

+0

流中的「底層媒體」是什麼? –

+0

取決於流。 'fstream'表示一個文件作爲底層介質。 'cin'和'cout'坐在控制檯的頂部,並且該控制檯可以讀取或寫入任何東西,但通常是屏幕,串行端口或網絡套接字。 'stringstream'的媒介是一塊內存。 – user4581301

1

作者和帖子都是正確的。

stream << std::endl實際上是stream << '\n' << std::flush。顯式刷新具有性能缺陷,這就是爲什麼你不應該在性能嚴重的情況下使用它。在調試時你很少考慮這種可忽略的性能問題,所以它實際上是顯式刷新調試輸出的一個很好的做法。

0

默認std::cout鏈接到stdout,這是...

完全緩衝當且僅當該流可以被確定爲不是指 到交互設備。

(C99,7.19.3文件,第7段)

這意味着,如果你的輸出發送到終端,std::endl"\n"使得在首位沒有區別。 ;-)


關於您的實際問題:

無論是真實的:

  • 未刷新輸出緩衝器可導致約在程序崩潰
  • 沖洗不正確的推論輸出緩衝區影響性能

一旦添加「always」,這隻會成爲一個問題。

什麼時候應該使用std::endl

當你想要刷新緩衝區。

作者是錯的還是我錯過了解他所說的任何部分?

我認爲絕對的量詞如「總是」,「全部」,「從不」等等,就風格/設計等而言,應該與一粒鹽一起服用。

(例外:決不調用未定義行爲;-))

你能不能給任何真實世界的場景沖洗輸出流的實際需要?

每當沒有最新輸出實際上出現不會被接受。這種情況在任何情況下都是一個判斷呼叫。

就個人而言,我會考慮生產/事務日誌是比調試日誌的關鍵...

0

1)當你應該使用std :: ENDL?

當你想確保緩衝區立即被刷新。

2)作者是否錯誤或我錯過了解他所說的 的任何部分?

不,作者是對的,你也是。

3)你可以給任何真實世界的情況下實際需要衝洗 輸出流嗎?

當particual字符串寫入流很多倍的時間std::endl短量的確可能導致性能損失,因爲每一次緩衝的不必要的沖洗。但是,對於僅用於調試目的而添加的打印行,應始終刷新緩衝區。再次,如果你正在使用打印行調試應用程序而不使用調試器,那麼你首先會做錯某些事情。

-7

你不應該使用std::endl。這是一個必須消失的貨運邪教。給你帶來的只是性能上的缺陷。只是讓它成爲一種肌肉記憶:總是"\n",從來沒有std::endl

+0

Downvote所有你會,這是我的長期立場。順便說一句,同步記錄必須廢除。 – SergeyA

+3

「永不」與「永遠」在同一聯盟中:我不喜歡這些背景下的絕對言論,它們造成的傷害比好的要多。不過,我已經失望了,你已經得到了你的份額。 ;-) – DevSolar

+0

@DevSolar,如何'一個人不應該使用原始的擁有指針'?有時候永遠不會意味着永遠。 – SergeyA

7

調試輸出應寫入std::cerr;它的單位緩衝,所以每個角色都會被刷新。很少需要std::endl,並且習慣使用它會導致代碼速度很慢。除非您知道需要刷新緩衝區,否則只需使用'\n'即可。

相關問題