13.7.2 迭代器适配器
从某种意义上讲,前面介绍的流迭代器也是迭代器适配器,此外还包括反向迭代器和插入迭代器。同使用流迭代器一样,使用反向和插入迭代器都必须包含头文件<iterator>。
1.反向迭代器
reverse_iterator的用法很有趣,对其执行递增操作会导致其递减。只要将reverse_iterator使用于原来正向访问的函数中,便可实现对容器的逆向操作。对常用容器来说(3种序列式容器和4种关联式容器),其内部都定义了reverse_iterator类,例如代码13.18用于反向输出容器中的元素。
代码13.18 反向迭代器的使用ReverseIterator
<————————————文件名:example1318.cpp——————————————-> 01 #include<iostream> 02 #include<iterator>//使用reverse_iterator和ostream_iterator包含的头文件 03 #include<vector> 04 using namespace std; 05 int main() 06 { 07 int sz[5]={1,2,3,4,5}; 08 vector<int>ob(sz,sz+5);//创建vector<int>对象 09 ostream_iterator<int,char>osi(cout,"");//创建输出流迭代器 10 vector<int>:reverse_iterator ri=ob. rbegin();//创建反向迭代器 11 copy(ri,ob. rend(),osi);//输出操作 12 cout<<endl; 13 return 0; 14 }
输出结果如下所示。
5 4 3 2 1
【代码解析】代码第11行在不改变copy接口的情况下,使用copy函数将ob中的元素逆序复制到输出流中输出。
2.插入迭代器适配器
STL中提供了3种插入迭代器适配器,即back_insert_iterator、front_insert_iterator和insert_iterator。使用这3种迭代器适配器时必须包括头文件<iterator>,这3种迭代器适配器将容器类型作为模板参数,换言之,插入迭代器适配器是依托于容器的,在创建迭代器时有两种格式,如下例所述。
❑back_insert_iterator<vector<int>>back_it(obV);
front_insert_iterator<queue<int>>front_it(obQ);
insert_iterator<list<int>>insert_it(obL,p);
❑back_inserter(ob1);
front_inserter(ob2);
inserter(ob3,p);
其中,第1种格式是根据类模板来创建插入迭代器适配器对象的,第2种格式是调用STL提供的函数并根据容器对象来返回相应的插入迭代器适配器对象。两者的不同之处在于第1种方式必须指明容器类型,之所以要这么做是因为插入迭代器必须要使用合适的容器方法。例如,back_insert_iterator的构造函数认为传递给其的容器对象类型有push_back()成员方法。
代码13.15 中使用第2种格式创建了匿名的back_insert_iterator对象。下面来看为何要使用插入迭代器对象,首先请读者尝试对代码13.15进行更改,将back_inserter(ob)替换成ob.begin(),编译时没有错误,可运行时程序会崩溃,原因在于copy是个独立的函数,没有重新调增容器大小的权限,而ob在建立时是个空容器,此时无法通过copy向ob中写入任何数据。
3种插入迭代器适配器通过复制转换和自动内存分配确保新信息的容纳,避免了对原有信息的覆盖,back_insert_iterator将元素插入到容器的尾部,front_insert_iterator将元素插入到容器的头部,insert_iterator将元素插入到其构造函数中迭代器参数p指定位置的前面,这3种迭代器属于输出迭代器。
注意
因为vector容器不能满足front_insert_iterator的要求,所以不能基于vector创建front_insert_iterator对象。
技巧通过插入迭代器适配器可以将复制算法转换成插入算法。