這部分主要講了常用迭代器用法的一些方面,分析STL中iterator、const_iterator、reverse_iterator和const_reverse_iterator的關係和一些轉換,其內容比較少,簡單。
Item26:Prefer iterator to const iterator, reverse_iterator, and const_reverse_iterator.
先看下四種迭代器之間的關係:
其中有些是可以通過隱式轉換得到,而有些則要通過base()成員函數得到。在vector方法insert、erase中接受參數的都是iterator類型。盡量用iterator替代其他迭代器的原因主要如下:1、insert和erase的一些版本要求iterator。2、const_iterator不能隱式轉換為iterator,手寫轉換不普遍且不高效。3、從reverse_iterator轉換而來的iterator在轉換之後可能需要相應的調整。iterator和const_iterator之間的比較可能會帶來一些麻煩,考慮下面代碼:
typedef deque<int> IntDeque;typedef IntDeque::iterator Iter;typedef IntDeque::const_iterator ConstIter;Iter i;ConstIter ci;...if (i == ci) ...
比較過程會將iterator隱式轉換成const_iterator,若有些實現將const_iterator的=操作符設為成員函數而不是非成員函數,那麼這段代碼就通不過,簡單的解決方案是將i和ci位置互換。而在const和非const的隨機訪問迭代器之間進行算術運算時,則必須用static_case將iterator強制轉換const_iterator。
Item 27. Use distance and advance to convert a container's const_iterators to iterators.一般情況不能講const_iterator用static_cast揮著其他方式轉換為iterator,而reverse_iterator和const_reverse_iterator是類,更不能強制轉換。他們之間的轉換可以用distance和advance來實現,如下代碼:
typedef deque<int> IntDeque;typedef IntDeque::iterator Iter;typedef IntDeque::const_iterator ConstIter;IntDeque d;ConstIter ci;...Iter i(d.begin());advance(i, distance(i, ci));
上述代碼有一個問題,distance參數是兩個InputIterator類型的迭代器,而i和ci是兩個不同類型迭代器,解決的方法是顯式聲明參數:
advance(i, distance<ConstIter>(i, ci));
上訴轉換的效率可能是線性時間,這取決於distance的時間,對不同類型的iterator不同。
Item 28. Understand how to use a reverse_iterator's base iterator.reverse_iterator通過base()可以得到對應的iterator,其具體的關係如下:
若要刪除rt所指的元素,我們可以將其轉換為iterator,然後刪除,如下:
vector<int> v;...vecot<int>::reverse_iterator ri = find(v.rbegin(), v.rend(), 3);v.erase(--ri.base());
但對於vector和string,有些實現的iterator採用內建指標,c/c++都規定不能直接修改函數返回的指標,那麼我們可以調整reverst_iterator來避免修改base()返回的值:
v.erase((++ri).base());
Item 29. Consider istreambuf_iterators for character-by-character input.考慮將一個文字檔拷貝到一個字串中:
ifstream inputFile("interestingData.txt");string fileData((istream_iterator<char>(inputFile)),istream_iterator<char>());
這種方法無法將檔案中的空格拷貝到字串中,istream_iterator使用>>操作符來讀取,預設忽略空格。一種方法是清除skipws標誌:
inputFile.unset(ios::skipws);
但是這種方式的效率不是很高,operator>>是格式化輸入,每次調用需要做大量的操作如建立和銷毀sentry對象,檢查流標誌(skipws等),錯誤檢查,異常處理等等。STL提供了一個高效的工具:istreambuf_iterators。像istream_iterator<char>對象使用operator>>來從輸入資料流中讀取單個字元,istreambuf_iterator<char>對象進入流的緩衝區並直接讀取下一個字元,我們可以改變如下:
ifstream inputFile("interestingData.txt");string fileData((istreambuf_iterator<char>(inputFile)),istreambuf_iterator<char>());
istreambuf_iterator不忽略任何字元,不需要改變skipws標誌,可以考慮把ostreambuf_iterator用於無格式字元的輸出。