有的時候會在題目中看到這麼一句:「建議使用 scanf
/printf
,使用 cin
和 cout
可能造成 TLE。」在輸入、輸出量比較大的題目,應該都可以明顯感受到 stdio
和 iostream
兩個的差異,scanf
和 printf
的效率顯然高得多,但是事情並不是這樣。
cin
和 cout
的好處很明顯,像是它們保證類型安全,不會像 printf
和 scanf
有打錯類型的風險,且 <<
和 >>
這兩個運算子可以重載,換句話說,你可以在定義一個類型的物件 a
如何輸入輸出後,方便的使用 cin >> a
和 cout << a
,就可以做到輸入輸出,既方便又直觀。
再加上 cout
像是補 0、控制位數等等都比 printf
好寫得多,所以事實上 cin
和 cout
是比較方便的,然而,速度似乎慢很多?先來看看為什麼:
在文字被輸出前,它會先到緩衝區,不是馬上就全部輸出,而是到一個特定的時間再一次輸出出去,因為分次輸出其實算是很耗資源的事。
緩衝區的 flush 是決定效率的關鍵因素,看是一次 flush、還是多次 flush,速度就會大有不同。printf
是不會自動 flush 的,scanf
也不會強制 flush,但 cin
就會了,因為在要求使用者輸入之前,應該先讓使用者看見先前輸出的文字,這是介面設計上的考量,但顯然不符合競程的需要,因此我們要取消強制 flush: 1
cin.tie(0);
tie
是 ios
的一個方法,也就是說,cin
、cerr
、cout
都有這個方法,cin
和 cerr
預設是有 tie cout
的,所以在使用 cin
、cerr
時,cout
的緩衝區會先被釋放,tie(0)
就可以解除。所以如果你不想看到 cerr
和 cout
的訊息全部卡在一起,可以再加上 cerr.tie(0)
。
接下來,還有一個地方會自動 flush,就是 endl
,也就是說,cout << endl
其實是 cout << flush << '\n'
,解決方法很簡單,就是不要用,都用 cout << '\n'
就可以了。
最後,還有一個跟緩衝區無關的問題,C++ 中有兩種輸入輸出系統:stdio
和 iostream
,因為一些歷史因素,C++ 會讓 iostream
和 stdio
同步,來避免混用時發生無法預期的問題,所以這個額外的動作會造成效率降低,不過打競程時不會有混用的狀況,把同步解除就好: 1
ios_base::sync_with_stdio(false);
iostream
和 stdio
不能混用。)