迭代器是一个纯粹的抽象概念:任何东西,只要其行为类似迭代器,它就是一个迭代器。因此,你可以撰写一些类别(classes),具备迭代器接口,但有着各不相同的行为。C++标准程序库提供了数个预先定义的特殊迭代器,亦即所谓迭代器配接器(iterator
adapters)。它们不仅起辅助作用,还能赋予整个迭代器抽象概念更强大的能力。
1、Insert iterators (安插型迭代器)
2、Stream iterators (流迭代器)
3、Reverse iterators (逆向迭代器)
Stream iterators
Stream迭代器是一种迭代器配接器,通过它,你可以把stream当成算法的原点和终点。更明确的说,一个istream迭代器可以用来从input stream中读元素,而一个ostream迭代器可以用来对output stream写入元素。Stream迭代器的一种特殊形式是所谓的stream缓冲区迭代器,用来对stream缓冲区进行直接读取和写入操作。
Ostream迭代器可以被赋予的值写入output stream中。下表列出ostream迭代器的各项操作。
算式 |
效果 |
ostream_iterator<T>(ostream) |
为ostream产生一个ostream迭代器 |
ostream_iterator<T>(ostream, delim) |
为ostream产生一个ostream迭代器,各元素间以delim为分隔符(请注意,delim的型别是const char*) |
*iter |
无实际操作(传回iter) |
iter = value |
将value写到ostream,像这样:ostream<<value。其后再输出一个delim(分隔符;如有定义的话) |
++iter |
无实际操作(传回iter) |
iter++ |
无实际操作(传回iter) |
#include<iostream> #include<vector> #include<algorithm> #include<iterator> using namespace std; int main() { ostream_iterator<int> intWriter(cout, " "); *intWriter = 43; intWriter++;//无实际操作 *intWriter = 77; intWriter = -5; vector<int> coll; for (int i = 1; i <= 9; ++i) { coll.push_back(i); } copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; system("pause"); }
输出:
43
77
-5
1 2 3 4 5 6 7 8 9
istream迭代器是ostream迭代器的拍档,用来从input
stream读取元素。透过istream迭代器,算法可以从stream中直接读取数据。istream迭代器的各项操作。产生一个istream迭代器时,必须提供一个input
stream作为参数,迭代器从中读取数据。然后它便经由input迭代器的一般接口,利用operator<<读取数据。然而,读取动作有可能失败(可能到达文件尾部,或读取错误),此外算法也要知道区间是否到达终点。为解决这些问题,可以使用一个end_of_stream迭代器,可以利用默认构造函数生成。只要有任何一次读取失败,所有istream迭代器都会变成end_of_stream迭代器,所以进行一次读取后, 应该将istream迭代器和end_of_stream迭代器比较一番。
算式 |
效果 |
istream_iterator<T>() |
产生一个end-of-stream迭代器 |
istream_iterator<T>(istream) |
为istream产生的一个迭代器(可能立即去读第一个元素) |
*iter |
传回先前读取的值(如果构造函数并未立刻读取第一个元素值,则本式执行读取任务) |
iter->member |
传回先前读取的元素的成员(如果有的话) |
++iter |
读取下一个元素,并传回其位置 |
iter++ |
读取下一个元素,并传回迭代器指向前一个元素 |
iter1 == iter2 |
检查iter1和iter2是否相等 |
iter1 != iter2 |
检查iter1和iter2是否不相等 |
注意:istream迭代器的构造函数会打开stream,读取第一个元素。所以,不要过早定义它。如果满足一下条件我们说两个istream迭代器相等:
两者都是end_of_stream迭代器
两者都可以再进行读取操作(未变为end_of_stream迭代器),并指向相同的stream。
#include<iostream> #include<iterator> using namespace std; int main() { istream_iterator<int> intReader(cin); istream_iterator<int> intReaderEOF; while (intReader != intReaderEOF) { cout << "once:" << *intReader << endl; cout << "once again:" << *intReader << endl; ++intReader; } system("pause"); }
输出:字符f导致程序结束。
1 2 3 f 4
once:1
once again:1
once:2
once again:2
once:3
once again:3
Stream迭代器的另一个例子:
#include<iostream> #include<iterator> #include<string> #include<algorithm> using namespace std; int main() { istream_iterator<string> cinPos(cin); ostream_iterator<string> coutPos(cout, " "); istream_iterator<string> intReaderEOF; while (cinPos != intReaderEOF) { advance(cinPos, 2); if (cinPos != intReaderEOF)//跳过两个位置后是否到达end_of_stream { *coutPos++= *cinPos++; } } cout << endl; system("pause"); }
输入:
No one objects if you are doing a good programming job for someone who you respe
ct.
输出:
objects are good for you
Reverse Iterators
逆向迭代器重新定义递增运算和递减运算,使其行为正好倒置。
deque<int>::iterator pos1,pos2;//coll元素:1,2,3,4……9 pos1=find(coll.begin(),coll.end(),2); pos2=find(coll.begin(),coll.end(),7); for_each(pos1,pos2,print); //输出:2 3 4 5 6 deque<int>::reverse_iterator rpos1(pos1); deque<int>::reverse_iterator rpos2(pos2); for_each(rpos2,rpos1,print); //输出:6 5 4 3 2
迭代器pos1和pos2定义了一个半开区间,包括2不包括7。当把描述这一区间的两个迭代器转换为Reverse迭代器时,该区间仍然有效,而且可以被逆序处理。
将迭代器转换为逆向迭代器:container::reverse_iterator(it);//it为迭代器
将逆向迭代器转换回来:rpos.base();//rpos为逆向迭代器
Insert iterators
Insert迭代器,也称为inserters,用来将“赋值新值”操作转换为“安插新值”操作。通过这种迭代器,算法可以执行安插(insert)行为而非覆盖(overwrite)行为。所有Insert迭代器都隶属于Output迭代器类型,所以它只提供赋值(assign)新值的能力。通常算法会将数值赋值给目的迭代器,如copy()算法
namespace std{ template<class Inputiterator,class Outiterator,Outputiterator> Outputiterator copy(Inputiterator from_pos,Inputiterator from_end,Outputiterator to_pos) { while(from_pos!=from_end) { *to_pos=*from_pos; ++from_pos; ++to_pos; } } }
*to_pos=*from_pos;
insert迭代器可以把上述这样的赋值转化为安插操作。不过实际上里面有两个操作:首先operator*传回迭代器当前位置(为何不是值,看下面表),然后再由operator=赋值新值,即安插操作。注意:
1、operator*被视作一个无实际动作的动作(no-op),简单返回一个*this,对于insert迭代器来说,*pos与pos等价。
2、赋值动作被转化为安插操作,事实上insert迭代器会调用push_back(),push_front()或insert()成员函数。
下表列出Insert迭代器的所有操作函数。
表达式 |
效果 |
*iter |
无实际操作(传回iter) |
iter = value |
安插value |
++iter |
无实际操作(传回iter) |
iter++ |
无实际操作(传回iter) |
C++标准程序库提供三种Insert迭代器:back
inserters, front inserters, general inserters。它们的区别在于插入位置。事实上它们各自调用所属容器中不同的成员函数。所以Insert迭代器初始化时要清楚知道自己所属的容器是哪一种。每一种insert迭代器都可以由一个对应的便捷函数加以生成和初始化。下表列出不同的insert迭代器及其能力。
名称 |
Class |
其所调用的函数 |
便捷函数 |
Back inserter |
back_inserter_iterator |
push_back(value) |
back_inserter(cont) |
Front inserter |
front_insert_iterator |
push_front(value) |
front_inserter(cont) |
General inserter |
insert_iterator |
insert(pos, value) |
inserter(cont, pos) |
back inserters(安插于容器最尾端),内部调用push_back(),在容器尾端插入元素。只有支持push_back()的vector、deque、list、string可以使用Back inserters。
#include<iostream> #include<vector> #include<algorithm> #include<iterator> using namespace std; int main() { vector<int> coll; back_insert_iterator<vector<int>> iter(coll); iter = 1; *iter = 2;//等价iter=1 ++iter;//无实际操作 iter++;//无实际操作 iter = 3; copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; back_inserter(coll) = 44; back_inserter(coll) = 45; copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; coll.reserve(2 * coll.size()); copy(coll.begin(), coll.end(), back_inserter(coll)); copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; system("pause"); }注意,一定要在调用copy()之前确保有足够大的空间,因为back inserter在安插元素时,可能会造成指向该vector的其它迭代器失效。
输出:
1 2 3
1 2 3 44 45
1 2 3 44 45 1 2 3 44 45
Front inserters(安插于容器最前端),内部调用push_front(),在容器前端插入元素。只有支持push_front()的deque、list可以使用Front inserters。
#include<iostream> #include<list> #include<algorithm> #include<iterator> using namespace std; int main() { list<int> coll; front_insert_iterator<list<int>> iter(coll); iter = 1; *iter = 2;//等价iter=1 ++iter;//无实际操作 iter++;//无实际操作 iter = 3; copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; front_inserter(coll) = 44; front_inserter(coll) = 45; copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; copy(coll.begin(), coll.end(), front_inserter(coll)); copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; system("pause"); }输出:
3 2 1
45 44 3 2 1
1 2 3 44 45 45 44 3 2 1
General inserters(一般性安插器),内部调用insert(),将元素插入到pos所指位置的前方。所有STL容器都提供insert()成员函数,所以这是唯一可用于关联式容器的预定义inserter。根据两个参数初始化:容器和待安插位置。安插操作完成后,General inserters获得刚刚被安插的那个元素的位置,实际上相当于以下语句:
pos=container.insert(pos,value); ++pos;然后新获得的位置再下次安插时使用。
#include<iostream> #include<set> #include<list> #include<algorithm> #include<iterator> using namespace std; int main() { set<int> coll; insert_iterator<set<int>> iter(coll,coll.begin()); iter = 1; *iter = 2;//等价iter=1 ++iter;//无实际操作 iter++;//无实际操作 iter = 3; copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; inserter(coll, coll.begin()) = 44; inserter(coll, coll.begin()) = 45; copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; list<int> coll2; copy(coll.begin(), coll.end(), inserter(coll2,coll2.begin())); copy(coll2.begin(), coll2.end(), ostream_iterator<int>(cout, " ")); cout << endl; copy(coll.begin(), coll.end(), inserter(coll2, ++coll2.begin())); copy(coll2.begin(), coll2.end(), ostream_iterator<int>(cout, " ")); cout << endl; system("pause"); }输出:
1 2 3
1 2 3 44 45
1 2 3 44 45
1 1 2 3 44 45 2 3 44 45