迭代器类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容器中所含元素的遍历.有这么几种迭代器如下: 迭代 ...
随机推荐
- Dual transistor improves current-sense circuit
In multiple-output power supplies in which a single supply powers circuitry of vastly different curr ...
- 插值技术之Bezier插值(1) -- Bezier Curve
作者:i_dovelemon 来源:CSDN 日期:2015 / 7 / 11 主题:Interpolate,Bezier Curve 引言 在游戏开发中.诸如动画系统.路径计算等等操作,都会遇到对数 ...
- Eclipse开发Java程序入门,HelloWord
今天看到一个专业的学术程序是Java写的,而我经常用的是Matalb,所以感觉十分不舒服.之前学的Java开发感觉也忘光了,所以感觉,知识必须要总结好,不然容易忘记.这也就是我写这篇文章的原因.希望能 ...
- DELPHI PROTOBUF免费的开源支持库fundamentals5
DELPHI PROTOBUF免费的开源支持库fundamentals5 1.源码URL: https://github.com/fundamentalslib/fundamentals5 2.编译P ...
- Ant:Ant 入门
背景 自从有了 Maven 以后,Ant 视乎就不流行了,不过 Ant 还是有其应用场景的,Ant 的思想比较简洁,如下: 一个 project 包含多个 target(类似成员方法). 一个 tar ...
- 关于Mantis变更日志(Changelog)和路线图(Roadmap)的说明
变更日志(Changelog):是已经修改好了问题的日志,需要给项目添加版本号,并且在添加/解决问题时都指定了相应的版本号,才会显示. 路线图(Roadmap):是计划在某个版本修改某些问题的日志,需 ...
- python的异常机制使用技巧
1.当你开发的接口被其他应用调用时,响应要及时,但是有些要触发的操作很耗时间. 比如下面需要通过被调用触发的函数create_job_1().但是这个函数执行会比较消耗时间 2.于是,我们可以利用异常 ...
- 漏洞预警 | ECShop全系列版本远程代码执行高危漏洞
2018年9月1日,阿里云态势感知发布预警,近日利用ECShop全系列版本的远程代码执行漏洞进行批量化攻击量呈上升趋势.该漏洞利用简单且危害较大,黑客可通过WEB攻击直接获得服务器权限. 漏洞原理 该 ...
- 一些LR的经验,讲的还不错
https://blog.csdn.net/Dinosoft/article/details/50492309 记录一下.
- Openwrt WIFI探针开发【一】
2017.9.26 公开源码(Apache2.0协议) https://github.com/769484623/WiFiProbe ————————————————————————————————— ...