C++中重新整理輸出緩衝區
每一個輸出流都管理一個緩衝區,用來儲存程式讀寫的資料。因此要將資料真正寫到輸出裝置中,就需要重新整理緩衝區。導致緩衝區重新整理的原因大體有以下5種。
1、程式正常結束,作為main函式return操作的一部分,緩衝區被重新整理。
2、當緩衝區滿了的時候,會重新整理緩衝區。
3、可以使用操作符endl、flush和ends來顯示的重新整理緩衝區。這三個都是IO庫中的操作符,endl能完成換行和重新整理緩衝區的工作。flush只完成重新整理緩衝區的工作。而ends會向緩衝區插入一個空字元,然後重新整理緩衝區。例子如下:
#include <algorithm> #include <string> #include <iterator> using namespace std; int main() { cout << "hi" << endl; cout << "hi" << flush; cout << "hi" << ends; cout << "hi"; system("pause"); return 0; }
編譯結果如下:
如上所述,ends向緩衝區插入了一個空格。我們可以觀察到,例子中最後一句並沒有使用任何操作符重新整理緩衝區,但是依舊將緩衝區的內容輸出出來了。顯然不可能是因為輸出緩衝區滿了的緣故,程式也沒有結束。這是因為當系統比較空閒的時候,會檢視緩衝區的內容,如果發現有新的內容,系統就會將緩衝區的內容輸出出來。不過這種重新整理是不可靠的,完全取決於系統的狀態,因此,我們最好使用上面的操作符來顯示重新整理緩衝區。
4、在每個輸出操作之後,我們可以用操作符unitbuf設定流的內部狀態,來清空緩衝區。設定了unitbuf操作符之後,在對緩衝區的每一次寫操作之後都會進行一次flush操作。相應的,可以設定nounitbuf操作符,使該輸出流恢復使用正常的系統管理的緩衝區重新整理機制。預設情況下,cerr流物件是已經設定了unitbuf的,因此每次寫到cerr的內容都會立即重新整理。設定unitbuf和nounitbuf的方法如下:
cout << unitbuf; //所有的輸出操作後都會立即重新整理緩衝區
cout << nounitbuf; //回到正常的緩衝方式
5、一個輸出流可能被關聯到另一個流。在這種情況下,當讀寫被關聯的流時,關聯到的流緩衝區會被重新整理。預設情況下,cin和cerr都關聯到cout。因此,讀cin或寫cerr都會導致cout的緩衝區被重新整理。關聯兩個流可以使用tie函式,其有兩個版本:
1)不帶引數,返回指向輸出流的指標。如果本物件當前關聯到一個輸出流,則返回的就是指向這個流的指標。如果該物件沒有關聯到流,則返回空指標。
2)接受一個指向ostream的指標,將自己關聯到此ostream。
注意:每個流同時最多關聯到一個流,但多個流可以同時關聯到同一個ostream。
最後,我們在除錯程式的時候要記住:程式出現異常終止的時候,輸出緩衝區是不會重新整理的(這和程式正常執行結束不一樣)。也就是說資料很可能還在緩衝區中,沒有輸出出來。