Effective STL條款29

需要一個一個字符輸入時考慮使用istreambuf_iterator

假設我們要把一個文本文件拷貝到一個字符串對象中。似乎可以用一種很有道理的方法完成:

很快你就會發現這種方法無法把文件中的空格拷貝到字符串中。那是因爲istream_iterators使用operator<<函數來進行真的讀取,而且operator<<函數在默認情況下忽略空格。

假如你想保留空格,你要的做就是覆蓋默認情況。只要清除輸入流的skipws標誌就行了:


現在inputFile中的所有字符都拷貝到fileData中了。

唉,你會發現它們的拷貝速度不像你想象的那麼快。istream_iterators所依靠的operator<<函數進行的是格式化輸入,這意味着每次你調用的時候它們都必須做大量工作。它們必須建立和銷燬崗哨(sentry)對象(爲每個operator<<調用進行建立和清除活動的特殊的iostream對象),它們必須檢查可能影響它們行爲的流標誌(比如skipws),它們必須進行全面的讀取錯誤檢查,而且如果它們遇到問題,它們必須檢查流的異常掩碼來決定是否該拋出一個異常。如果進行格式化輸入,那些都是重要的活動,但如果你需要的只是從輸入流中抓取下一個字符,那就過度了。

一個更高效的方法是使用STL最好的祕密武器之一:istreambuf_iterators。你可以像istream_iterator一樣使用istreambuf_iterator,但istream_iterator<char>對象使用operator<<來從輸入流中讀取單個字符。istreambuf_iterator<char>對象進入流的緩衝區並直接讀取下一個字符。(更明確地說,一個istreambuf_iterator<char> 對象從一個istream s中讀取會調用s.rdbuf()->sgetc()來讀s的下一個字符。)把我們的文件讀取代碼改爲使用istreambuf_iterator相當簡單,大多數Visual Basic程序員都可以在兩次嘗試內做對:


注意這裏不需要“unset”skipws標誌,istreambuf_iterator不忽略任何字符。它們只抓取流緩衝區的下一個字符。

相對於istream_iterator,它們抓取得更快——在我進行的簡單測試中能快40%,如果你的結果不同也不用驚奇。如果隨時間流逝,速度優勢不斷增加也不必奇怪,因爲istreambuf_iterator存在於STL的一個不常訪問的角落,所以實現還沒有花很多時間來優化。比如,在我用過的一個實現中,istreambuf_iterator在我的主要測試中只比istream_iterator快了大約5%。那樣的實現顯然還有很多餘地來優化它們的istreambuf_iterator實現。如果你需要一個一個地讀取流中的字符,你不需要格式化輸入的威力,你關心的是它們花多少時間來讀取流,和明顯的性能提高相比,爲每個迭代器多鍵入三個字符的代價是微弱的。對於無格式的一個一個字符輸入,你總是應該考慮使用istreambuf_iterator。

當你瞭解它之後,你也應該考慮把ostreambuf_iterator用於相應的無格式一個一個字符輸出的作。它們沒有了ostream_iterator的開銷(和彈性),所以它們通常也做得更好。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章