頭文件<iterator>中定義了四種迭代器:
- 插入迭代器(insert iterator):這些迭代器被綁定到一個容器上,可向容器插入元素铣除。
- 流迭代器(stream iterator):這些迭代器被綁定到輸入或輸出流上问慎,可用來遍歷關聯(lián)的IO流嫡良。
- 反向迭代器(reverse iterator):這些迭代器向后而不是向前移動绢涡。除了forward_list之外的標準庫容器都有反向迭代器。
- 移動迭代器(move iterator):這些專用的迭代器不是拷貝其中的元素纹冤,而是移動它們洒宝。
插入器是一種迭代器適配器,它接受一個容器萌京,生成一個迭代器雁歌,能實現(xiàn)向給定容器添加元素。當我們通過一個插入迭代器進行賦值時知残,該迭代器調用容器操作來向給定容器的指定位置插入一個元素靠瞎。it = t; 即在it指定的當前位置插入值t。假定c是it綁定的容器求妹,依賴于插入迭代器的不同種類乏盐,此賦值會分別調用c.push_back(t), c.push_front(t)或c.insert(t, p), 其中p為傳遞給inserter的迭代器位置制恍。
與上面相對應父能,插入器有三種類型,back_inserter, front_inserter, inserter吧趣,差異在于元素插入的位置法竞。
list<int> lst = {1, 2, 3, 4};
list<int> lst2, lst3;
//拷貝完成之后,lst2包含4 3 2 1
copy(lst.cbegin(), lst.cend(), front_inserter(lst2) );
//拷貝完成之后强挫,lst3包含1 2 3 4
copy(lst.cbegin(), lst.cend(), inserter(lst3, lst3.begin() ) );
iostream迭代器岔霸,istream_iterator讀取輸入流,ostream_iterator向一個輸入流中寫數(shù)據(jù)俯渤。這些迭代器呆细,將他們對應的流當做一個特定類型的元素序列來處理。通過使用流迭代器八匠,我們可以用泛型算法從流對象讀取數(shù)據(jù)以及向其寫入數(shù)據(jù)絮爷。
istream_iterator的一些操作
istream_iterator<int> int_it(cin);
istream_iterator<int> int_eof;
ifstream in("afile");
istream_iterator<string> str_it(in);
istream_iterator<int> in_iter(cin);
istream_iterator<int> eof;
while (in_iter != eof)
//后置遞增運算讀取流,返回迭代器的舊值
//解引用迭代器梨树,獲得從流讀取的前一個值
vec.push_back(*in_iter++);
//上面的一小段程序可以重寫為如下形式:
istream_iterator<int> in_iter(cin), eof;
vector<int> vec(in_iter, eof);
//使用算法操作流迭代器
istream_iterator<int> in(cin), eof;
cout << accumulate(in, eof, 0) << endl;
istream_iterator允許懶惰求值坑夯,也即是當我們將一個istream_iterator綁定到一個流時,標準庫并不保證迭代器立即從流讀取數(shù)據(jù)抡四。具體實現(xiàn)可以推遲從流中讀取數(shù)據(jù)柜蜈,直到我們使用迭代器時才真正讀取。標準庫中的實現(xiàn)所保證的是指巡,在我們第一次解引用迭代器之前淑履,從流中讀取數(shù)據(jù)的操作已經(jīng)完成了。對于大多數(shù)程序來說藻雪,立即讀取還是推遲讀取沒什么差別秘噪。但是,如果我們創(chuàng)建了一個istream_iterator勉耀,沒有使用就銷毀了指煎,或者我們正在從兩個不同的對象同步讀取同一個流蹋偏,那么何時讀取可能就很重要了。
ostream_iterator創(chuàng)建時贯要,可以提供(可選的)第二參數(shù)暖侨,它是一個字符串,在輸出每個元素后都會打印此字符串崇渗。此字符串必須是一個C風格字符串(即字逗,一個字符串字面常量或者一個指向以空字符結尾的字符數(shù)組的指針)。必須將ostream_iterator綁定到一個指定的流宅广,不允許空的或表示尾后位置的ostream_iterator葫掉。
//用ostream_iterator來輸出值的序列
ostream_iterator<int> out_iter(cout, " ");
for(auto e : vec)
*out_iter++ = e;
cout << endl;
//下面的程序與上面的等價
for(auto e : vec)
out_iter = e;
cout << endl;
運算符*和++實際上對ostream_iterator對象不做任何事情,因此忽略它們對我們的程序沒有任何影響跟狱。但是俭厚,推薦第一種形式。在這種寫法中驶臊,流迭代器的使用與其他迭代器的使用保持一致挪挤。如果想將此循環(huán)改為操作其他迭代器類型,修改起來非常容易关翎。而且扛门,對于讀者來說,此循環(huán)的行為也更加清晰纵寝。
可以通過調用copy來打印vec中的元素论寨,這比編寫循環(huán)更為簡單:
copy(vec.begin(), vec.end(), out_iter);
cout << endl;
反向迭代器就是在容器中從尾元素向首元素反向移動的迭代器。對于反向迭代器爽茴,遞增(以及遞減)操作的含義會顛倒過來葬凳。遞增一個反向迭代器(++it)會移動到前一個元素;遞減一個元素(--it)會移動到下一個元素室奏。
反向迭代器與普通迭代器的關系火焰,rcomma如果是一個反向迭代器,那么rcomma.base()就是一個正向迭代器胧沫。
新標準庫中定義了一種移動迭代器(move iterator)適配器昌简,一個移動迭代器通過改變給定迭代器的解引用運算符的行為來適配此迭代器。一般來說琳袄,一個迭代器的解引用運算符返回一個指向元素的左值江场。與其他迭代器不同纺酸,移動迭代器的解引用運算符生成一個右值引用窖逗。
我們通過調用標準庫的make_move_iterator函數(shù)將一個普通迭代器轉換為一個移動迭代器。此函數(shù)接受一個迭代器參數(shù)餐蔬,返回一個移動迭代器碎紊。
原迭代器的所有其他操作在移動迭代器中都照常工作佑附。由于移動迭代器支持正常的迭代器操作,我們可以將一對移動迭代器傳遞給算法仗考。
值得注意的是音同,標準庫不保證哪些算法適用移動迭代器,哪些不適用秃嗜。由于移動一個對象可能銷毀原對象权均,因此你只有在確信算法在為一個元素賦值或將其傳遞給一個用戶定義的函數(shù)后不再訪問它時,才能將移動迭代器傳遞給算法锅锨。