前言
C++标准库中提供了数个预先定义的特殊迭代器,也就是所谓的迭代器配接器(iterator adapter),它不仅起到辅助作用,还能赋予整个迭代器更加强大的能力。就像任何东西其行为像函数,我们就可以认为是函数,这样特殊的函数我们称为仿函数;类似的,任何东西,只要其行为类似迭代器,它就是一个迭代器。因此我们可以撰写一些类别,使其具备迭代器接口,但有着各不相同的行为。这些特殊的迭代器就是我们说的迭代器配接器,STL中主要有三种迭代器配接器:
1.Insert Iterators (安插型迭代器)
2.Stream Iterators(流迭代器)
3.Reverse Iterators(逆向迭代器)
本文主要探讨安插型迭代器的类别和使用,先看一个例子。
例子一
int _tmain(int argc, _TCHAR* argv[]) { list<int> ilist; vector<int> iVec;//ivec初始未指定大小,默认是0 for (int i = 0; i < 6; i++) { ilist.push_back(i); } //iVec.resize(ilist.size()); 方式一 //copy(ilist.begin(), ilist.end(), back_inserter(iVec));//方式二:采用迭代器 back_inserter copy(ilist.begin(), ilist.end(), iVec.begin());//目标空间不足,运行奔溃 return 0; }结论:
1、执行copy算法时,必须确保目标空间有足够的大小,但ivec的空间大小为0,将源空间的值会逐一的赋值到目标空间ivec中,由于执行涂写操作(赋值),导致程序执行异常。
2、采用方式一、二都能确保足够的目标空间,方式二就是此次讨论的安插型迭代器,Insert Iterators会促使目标空间按需要增长。
Insert迭代器
Insert迭代器,也称为inserts,用来将“赋值新增”操作行为转换为“安插新值”操作,通过这种迭代器,算法可以执行安插(insert)操作而非覆盖行为,至于插入位置是在容器的前面或最后,或者某个特定的位置,须视三种不同的insert Iterator 而定。所有的Insert迭代器都属于Output迭代器类型。
通常算法会将数值赋值给标的迭代器。例如copy()算法:
namespace std { template <class InputIterator, class OutputIterator> OutputIterator copy(InputIterator from_begin, //beginning of source InputIterator from_end, //end of source OutputIterator to_pos) //beginning or dest { while (from_begin != from_end) { *to_pos = *from_begin; //copy value ++from_begin; //increment interator ++to_pos; } return to_pos; } }我们需要注意的是:*to_pos = values; Insert 迭代器内部会重载“=”,从而将赋值动作转为安插操作,具体见源码。这里分为两个操作:
1、operator* 是一个无实际动作的动作(no-op),只是简单的传回*this。因此对insert迭代器而言,*pos 与pos其实是等价。
2、赋值操作被转换为安插操作。不同的insert迭代器会调用容器内部的push_back(),push_front(),insert()成员函数。
如上描述,对于一个insert迭代器,我们写为 pos = value或者*pos=value。但从概念上理解,使用“*pos = value”更为正确, 如图表1是insert迭代器所有的操作函数。
Insert Iterator 分类
1. Back Inserters(安插于容器最尾端)
Back Inserters的内部调用push_back(),在容器的尾端插入元素,也只有能提供push_back()的成员函数的容器才能使用back insert迭代器,STL中有vector、deque、list。
2. Front Inserters(安插于容器最前端)
front inserts的内部调用push_front(),在容器的最前端插入元素,在STL 容器中能使用该迭代器的容器有deque、list;
3.General Inserters(一般性安插器)
对于这种安插型迭代器,简称inserts,该insers内部调用的成员函数是inserter(),并新值和新位置作为参数,所有的STL容器都提供inserter()成员函数,也是唯一能够作用于关联式容器的迭代器。我们知道对于关联式容器进行插入时,不能指定其位置,它的位置有键值决定,在关联式容器中我们给出的位置信息仅仅是一个提示作用,帮助它从什么地方开始搜寻正确的安插位置。
这里通过分析back_insert_iterator类为例讨论其功能,Back inserter重载operator=完成后端插入,其他类型的迭代器的插入也是通过重载operator=完成,只是调用的函数不同罢了。back_insert_iterator类源码代码如下:
template<class _Container> class back_insert_iterator: public _Outit { // wrap pushes to back of container as output iterator public: typedef _Container container_type; typedef typename _Container::reference reference; typedef _Range_checked_iterator_tag _Checked_iterator_category; explicit back_insert_iterator(_Container& _Cont) : container(&_Cont) { // construct with container } back_insert_iterator<_Container>& operator=( typename _Container::const_reference _Val) { // push value into container container->push_back(_Val); return (*this); } back_insert_iterator<_Container>& operator*() { // pretend to return designated value return (*this); } back_insert_iterator<_Container>& operator++() { // pretend to preincrement return (*this); } back_insert_iterator<_Container> operator++(int) { // pretend to postincrement return (*this); } protected: _Container *container; // pointer to container };
例子二
/**************************************************************** *函数名称:BackInsert *功 能:back insertor功能应用 *作 者:Jin *日 期:2016年6月2日 ****************************************************************/ void BackInsert() { vector<int> nVector;//creat empty vector for (int i = 1;i <= 3;i++) { nVector.push_back(i * 10); } //creat back_insert iterator back_insert_iterator<vector<int> > iter(nVector); *iter = 1; //push_back(1) iter++; //假装递增,无实际意义 iter = 2; //等同于 *iter = 2;push_back(2) *iter = 3; //push_back(3) //output: 10 20 30 1 2 3 PrintElements(nVector,"vector list:"); //create back inserter and insert element //convenient way back_inserter(nVector) = 44; back_inserter(nVector) = 54; deque<int> nDeque;//creat empty deque copy(nVector.begin(), nVector.end(),back_inserter(nDeque)); //Output: 10 20 30 1 2 3 44 54 PrintElements(nDeque, "queue list:"); }
例子三
void InsertIterator() { list <int> iList; for (int i = 1; i < 10; ++i) { iList.push_back(i); } vector<int> iVector; //back_inserter 插入末尾 copy(iList.begin(), iList.end(), back_inserter(iVector)); deque<int> iDeque; //front_inserter 插入首部 copy(iList.begin(), iList.end(), front_inserter(iDeque)); set<int> iSet; //only work for associative collections copy(iList.begin(), iList.end(), inserter(iSet, iSet.begin())); }