迭代器类vector::iterator 和 vector::reverse_iterator 的实现、迭代器类型、常用的容器成员
一、迭代器
迭代器是泛型指针
普通指针可以指向内存中的一个地址
迭代器可以指向容器中的一个位置
STL的每一个容器类模版中,都定义了一组对应的迭代器类。使用迭代器,算法函数可以访问容器中指定位置的元素,而无需关心元素的具体类型。
下面来稍微看一下vector<class>::iterator 和
vector<class>::reverse_iterator 的源码:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
template < class _Ty,
class _Alloc > class _Vector_val : public _CONTAINER_BASE_AUX_ALLOC<_Alloc> { // base class for vector to hold allocator _Alval protected: _Vector_val(_Alloc _Al = _Alloc()) : _CONTAINER_BASE_AUX_ALLOC<_Alloc>(_Al), _Alval(_Al) { // construct allocator from _Al } typedef typename _Alloc::template _Alty _Alval; // allocator object for values template < class _Ty, typedef _Vector_val<_Ty, _Ax> _Mybase;
typedef typename _Mybase::_Alty _Alloc; //_Alloc 的定义所在
typedef _Vector_iterator<_Ty, _Alloc> iterator; typedef _Vector_const_iterator<_Ty, _Alloc> const_iterator; // friend class _Vector_iterator<_Ty, _Alloc>; typedef std::reverse_iterator<iterator> reverse_iterator; template < class _Ty, template < class _Ty, typedef random_access_iterator_tag iterator_category;
typedef _Ty value_type; typedef typename _Alloc::difference_type difference_type; typedef typename _Alloc::const_pointer pointer; typedef typename _Alloc::const_reference reference; typedef const value_type _FARQ *const_pointer;
typedef const value_type _FARQ& const_reference; .... _Tptr _Myptr; // offset of element in vector }; template<class _Ty> typedef value_type _FARQ& reference;
... }; // TEMPLATE CLASS _Allocator_base template<class _RanIt> }; // TEMPLATE CLASS _Revranit |
typedef _Vector_iterator<_Ty, _Alloc> iterator; 可知iterator 只是类型定义,而_Vector_iterator
又继承自 _Vector_const_iterator,这
个类有个成员_Tptr _Myptr; 进一步看_Tptr 可以知道类型是value_type*, 假设现在使用的容器是vector<int>,那么value_type
也就是
即包装了一般的指针。很明显地,iterator 类里面一定重载了
operator*, ->, ++, -- 等操作符,而这些操作符实际上还是对一般的指针_Myptr 进行操作。举operator* 来说:
1
2 3 4 5 6 7 8 9 10 11 12 13 |
// iterator
reference operator*() const
{ // return designated object return ((reference) **(_Mybase *)this); } // const_iterator ..... |
(_Mybase *)this就是const_iterator*,*(_Mybase *)this就是const_iterator
对象,**(_Mybase *)this就是调用const_iterator
的 operator*(), 即 返回*_Myptr,即指向的元素,iterator 的 operator* 返回的是引用 reference
,这其实是在allocator 类中定义的const_reference,
即 const value_type&, 假设现在的容器是vector<int> ,那么返回的也就是const int& ,即不能将其作为左值进行赋值,但能作为右值,如
cout<<*it;
同样地, iterator 的 operator++ 也调用了 const_iterator 的 operator++, 在函数里面也是执行 ++_Myptr; 的操作,返回的是const_iterator& ,而从
iterator 的 operator++ 返回的是iterator& 。
typedef std::reverse_iterator<iterator> reverse_iterator; 再来看 reverse_iterator,继承自_Revranit, 这个类有个成员 _RanIt current;
也就是说有个 iterator 类成员,即包装了一个iterator 类成员,从这个角度看,reverse_iterator 也可以算是一个适配器,利用 iterator
类的一些操作完成自身的功能。
××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
上面介绍的是vector::iterator ,比如 list::iterator 实现是类似的,内部成员也是一个指针,不过是指向Node 结点的指针,如:
_Nodeptr _Ptr;// pointer to node
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include <vector>
#include <list> #include <iostream> using namespace std; int main(void) vector<int>::iterator it; vector<int>::reverse_iterator ri; list<int> l; list<int>::iterator it2; for (it2 = l.begin(); it2 != l.end(); ++it2) return 0; |
二、迭代器的类型 iterator_category
输入迭代器
可以用来从序列中读取数据
输出迭代器
允许向序列中写入数据
前向迭代器
既是输入迭代器又是输出迭代器,并且可以对序列进行单向的遍历
双向迭代器
与前向迭代器相似,但是在两个方向上都可以对数据遍历
随机访问迭代器
也是双向迭代器,但能够在序列中的任意两个位置之间进行跳转
下图是不同类型的迭代器能够实现的操作:
1、The standard-library container classes all support bidirectional iterators.
of curse the const iterator only meets the requirements for input iterators.
2、The vector and deque iterators are
random-access iterators. however, the list iterator is not; it supports
only bidirectional iterators.etc,it does not support [] operation.
3、If c is a container that supports
push_back, then back_inserter(c) is an output iterator that meets no
other iterator requirements.
4、The stream iterators are defined in the <iterator> header, the istream_iterator<class name> meets the requirements for input iterators; the ostream_iterator<class
name> meets the requirements for output iterators.
we can use it like this:
1
2 3 4 5 6 7 8 9 10 11 |
vector<int> v;
// read ints from the standard input and append them to v // istream_iterator<int>() indicate "EOF" copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(v)); // write the elements of v each seperated from other by a space // no seperation between elements! |
不同的迭代器支持不同的操作集,而各种算法也要求相应的迭代器具有最小的操作集。因此,可以将算法的迭代器分为下面五类:
除了输出迭代器,其他类别的迭代器形成了一个层次结构:需要低级类别迭代器的地方,可使用任意一种更高级的迭代器。例如,对于需要输入迭代器的算法,可传递前向、双向或随机访问迭代器调用该算法。而反之则不行。注意:向算法传递无效的迭代器类别所引起的错误,无法保证会在编译时被捕获到。
map, set, list类型提供双向迭代器,而string,
vector和deque容器上定义的迭代器都是随机访问迭代器,用作访问内置数组元素的指针也是随机访问迭代器。istream_iterator是输入迭代器,ostream_iterator是输出迭代器。
另外,虽然map和set类型提供双向迭代器,但关联容器只能使用这部分算法的一个子集。因为关联容器的键是const对象。因此,关联容器不能使用任何写序列元素的算法。只能使用与关联容器绑在一起的迭代器来提供用于读操作的实参。因此,在处理算法时,最好将关联容器上的迭代器视为支持自减运算的输入迭代器,而不是完整的双向迭代器。
三、常用的容器成员
下面列举的成员中,有一些是所有容器共有的,有些是特有的,注意区别:
四、迭代器失效的问题(摘自 http://blog.csdn.net/hackbuteer1/article/details/7734382)
vector迭代器的几种失效的情况:
1、当插入(push_back)一个元素后,end操作返回的迭代器肯定失效。
2、当插入(push_back)一个元素后,capacity返回值与没有插入元素之前相比有改变,则需要重新分配整个容器,此时first和end操作返回的迭代器都会失效。
3、当进行删除操作(erase,pop_back)后,指向删除点的迭代器全部失效;指向删除点后面的元素的迭代器也将全部失效。
deque迭代器的失效情况: 在C++Primer一书中是这样限定的:
1、在deque容器首部或者尾部插入元素不会使得任何迭代器失效。
2、在其首部或尾部删除元素则只会使指向被删除元素的迭代器失效。
3、在deque容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器失效。
list的迭代器好像很少情况下会失效,也许就只是在删除的时候,指向被删除节点的迭代器会失效吧,其他的还没有发现。
先看两条规制:
1、对于节点式容器(map, list, set)元素的删除、插入操作会导致指向该元素的迭代器失效,其他元素迭代器不受影响。
2、对于顺序式容器(vector)元素的删除、插入操作会导致指向该元素以及后面的元素的迭代器失效。
众所周之当使用一个容器的insert或者erase函数通过迭代器插入或删除元素"可能"会导致迭代器失效,因此建议我们获取insert或者erase返回的迭代器,以便用重新获取新的有效的迭代器进行正确的操作:
代码如下:
- iter = vec.insert(iter);
- iter = vec.erase(iter);
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范
迭代器类vector::iterator 和 vector::reverse_iterator 的实现、迭代器类型、常用的容器成员的更多相关文章
- C#设计模式:迭代器模式(Iterator Pattern)
一,什么是迭代器模式(Iterator Pattern) 提供一种方法顺序访问一个容器对象中的各个元素,而又不需要暴露该对象的内部表示 二,看下面例子: using System; using Sys ...
- JAVA迭代器学习--在JAVA中实现线性表的迭代器
1,迭代器是能够对数据结构如集合(ADT的实现)进行遍历的对象.在遍历过程中,可以查看.修改.添加以及删除元素,这是它与一般的采用循环来遍历集合中的元素不同的地方.因为,通常用循环进行的遍历操作一般是 ...
- 重写vector类,完成基本功能,不含迭代器
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
- C++ error C2440: “类型转换” : 无法从“std::vector::iterator”转换为“
原文地址:http://blog.csdn.net/onlyou930/article/details/5602654 圆环套圆环之迭代器 话说这一日是风平浪静,万里乌云,俺的心情好的没得说,收到命令 ...
- vector iterator not incrementable For information on how your program can cause an an assertion Failure, see the Visual c + + documentation on asserts
#include <list> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { list<int> sl ...
- 一天一个类,一点也不累 之 Vector
一天一个类,一点也不累. 今天要说的是ArrayList的亲兄弟--Vector 亲兄弟?看看“族谱” Class Vector<E> java.lang.Object java.util ...
- STL.vector.iterator的序号
ZC:网上查到,使用vector时,只要将 find到的iterator(itX)减去vector::begin() 就可以得到itX的序号. 1.需求:得到 某个 iterator在 vector中 ...
- STL 迭代器适配器(iterator adapter)
iterator adapter graph LR iterator --- reverse_iterator iterator --- Insert_iterator iterator --- io ...
- C++ Iterator迭代器介绍及Iterator迭代器用法代码举例
C++ Iterator迭代器介绍 迭代器可被用来访问一个容器类的所包函的全部元素,其行为像一个指针.举一个例子,你可用一个迭代器来实现对vector容器中所含元素的遍历.有这么几种迭代器如下: 迭代 ...
随机推荐
- 取maven copy部分
mvn deploy:deploy-file -DgroupId=com.mycompany -DartifactId=my-project -Dversion=1.0.0 -Dpackaging=j ...
- mysql 实验
http://yangyaru0108.blog.51cto.com/6616699/1205001
- java反射机制简单介绍
1.字节码.所谓的字节码就是当java虚拟机载入某个类的对象时,首先须要将硬盘中该类的源码编译成class文件的二进制代码(字节码),然后将class文件的字节码载入到内存中,之后再创建该类的对象 2 ...
- 无线AP和无线路由器区别wifi热点
转自:http://network.51cto.com/art/201310/413327.htm 就像很多用户很容易混淆无线上网卡和无线网卡一样,很多用户也分不清无线AP和无线路由,小峰便是其中的一 ...
- 数学图形(2.9) Capareda曲线
还是绕在球上的线圈 #http://www.mathcurve.com/courbes3d/capareda/capareda.shtml vertices = t = to (*PI) q = ra ...
- Orchard运用 - 如何删除部分内容显示
最近在潜心研究Orchard CMS,个人觉得要深入了解一个系统最好的办法, 就是使用它做些什么尝试,最好有些真实的实践,比如不妨基于Orchard搭建个人博客, 看看有哪些场景需要定制,哪些功能可以 ...
- unity 的reflection probe和environmentmap
unity做了个很恶心的事情 unity_SpecCube0这里如果在reflectionprobe范围内就传reflectionprobe 如果在probe范围外这里就传environmap 在GI ...
- TensorFlow进阶(六)---模型保存与恢复、自定义命令行参数
模型保存与恢复.自定义命令行参数. 在我们训练或者测试过程中,总会遇到需要保存训练完成的模型,然后从中恢复继续我们的测试或者其它使用.模型的保存和恢复也是通过tf.train.Saver类去实现,它主 ...
- CentOS7 常用命令集合
CentOS7 常用命令集合 文件与目录操作 touch test.txt: 创建一个文本文件 文本内容处理 查询操作 压缩.解压 yum安装器 网络相关 系统相关 XSheel 5相关操作 窗体快捷 ...
- 【Python】Django CSRF问题
参考资料: Django Ajax CSRF 认证:http://www.ziqiangxuetang.com/django/django-csrf.html Python Post遇到csrftok ...