[C++]高效使用迭代器的一些建議
迭代器
本文介紹四種迭代器的使用細節,已經相互轉換的方法,從而提高對迭代的理解和使用。
1. iterator優於const_iterator, const_reverse_iterator, reverse_iterator
iterator幾乎可以適用於所有需要迭代器為引數的函式呼叫。但其他的三種迭代卻不一定。
以下這張圖可以清晰地表明不同迭代器之間的轉換關係。
我們需要知道的是,有些版本的insert和erase是沒有給出const_iterator的過載版本的,所以如果要在相應位置做操作就必須把他們轉換為iterator才能進行。請注意,不要考慮強制型別轉換,這總是不太好的選擇。後面我們將給出轉換的方法。
2. const_iterator轉換為iterator
之前提到,不要考慮強制型別轉換,是因為這兩個型別是完全不同的型別!(對vector和string可能不適用)所以把兩個完全不同的型別相互轉換是非常沒有道理的。
(在vector和string裡,迭代器會被實現為T* 和 const T*,他們之間是可以進行隱式型別轉換的。)
所以,我們希望得到一種更加普遍可用的方法。
這裡我們需要使用兩個成員函式來解決這個問題。
#include <iostream>
#include <fstream>
#include <deque>
using namespace std;
int main() {
typedef deque<int> intDeq;
typedef intDeq::iterator iter;
typedef intDeq::const_iterator citer;
intDeq d;
citer ci;
iter i(d.begin());
advance(i, distance<citer>(i, ci));
return 0;
}
這裡需要注意的是不能直接呼叫distance函式。正如我們前面說的,iterator和const_iterator是兩個不一樣的型別,所以必須給出確定的型別來做比較。
效率上來說,這種方法對於隨機訪問的容器是常數時間操作,對於雙向迭代器來說是線性時間操作。所以效率上來說是不太好的。
3. 正確理解reverse_iterator的base函式
base函式並不是真正的把reverse_iterator轉換iterator, 其中還有一個偏移量的問題。
這是base呼叫的偏移量。
因為reverse本來就是從右往左遍歷,所以插入的操作理所應當在iter的右邊,所以insert操作和我們預想的結果是一樣的。
但是對於erase則不是這樣的。因為base會自動往右移一個偏移量,所以我們需要修正這個編譯量,例如,而這很簡單。
v_i.erase((++iter).base());
4. istreambuf_iterator來作為字元的輸入
除了傳統的使用檔案操作的方法,我們還可以使用迭代器來實現讀取檔案內容。
通過設定dataFile.unsetf(ios::skipws);
,我們可以實現忽略空格的輸入。
#include <iostream>
#include <fstream>
using namespace std;
int main() {
fstream dataFile("data.txt");
string str((istream_iterator<char>(dataFile)), istream_iterator<char>());
dataFile.unsetf(ios::skipws);
copy(str.begin(), str.end(), ostream_iterator<char>(cout));
return 0;
}
但更簡單的說法是:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
fstream dataFile("data.txt");
string str((istreambuf_iterator<char>(dataFile)), istreambuf_iterator<char>());
copy(str.begin(), str.end(), ostream_iterator<char>(cout));
return 0;
}