文章目录
- 1.迭代器
- 2.迭代器类型
- 3.迭代器源码剖析
- 4.反向迭代器
- 4.容器常用的成员
1.迭代器
- 迭代器是泛型指针
(1)普通指针可以指向内存中的一个地址
(2)迭代器可以指向容器中的一个位置,本质上就是内存地址
通过重载一些指针相关的运算符,*,指针运算符->,++,–等运算符来支持普通的指针操作,所以迭代器可以看成是一个泛型指针 - STL的每一个容器类模板中,都定义了一组对应的迭代器类。
使用迭代器,算法函数可以访问容器中指定位置的元素,而无需关心元素的具体类型。 - eg:
begin()指向第一个元素的位置,end()指向最后一个元素的下一个位置
2.迭代器类型
- 输入迭代器
可以用来从序列中读取数据
支持*操作(访问迭代器中所指向位置的元素),++操作,eg:不支持*p=0 - 输出迭代器
允许向序列中写入数据
支持*操作,++操作,eg:支持*p=0(向迭代器所指向的位置写入数据) - 前向迭代器
既是输入迭代器又是输出迭代器,并且可以对序列进行单向的遍历(只支持++操作,不支持–操作) - 双向迭代器
与前向迭代器相似,但是在两个方向上都可以对数据遍历(支持++,–操作) - 随机迭代器
也是双向迭代器,但能够在序列中的任意两个位置之间进行跳转(支持++,–操作,支持+5,-3,+=,-=操作) - 迭代器的类型表
3.迭代器源码剖析
- eg:P77\01.cpp
- 断点位置
- iterator就是一个模板类_Vector_iterator
- 迭代器的构造函数
vector中的迭代器类,实际上只有一个数据成员int*,相当于对int*进行包装,迭代器内部持有int*类型;
_Vector_iterator常量迭代器继承至_Vector_const_iterator常量迭代器,只是不能更改而已; - F11,调用基类的构造函数
- _Vector_const_iterator与普通iterator的区别是啥?
_Vector_const_iterator中pointer是_Alloc中的const_pointer,实际上传递进来的类是int类型,所以pointer的类型是int*类型,const_reference实际上就是const int &,
_Vector_const_iterator迭代器就是对指针的一种包装,是泛型指针,提供了一些指针相关的运算符来支持普通指针的一些操作。 - _Vector_const_iterator里面有一个数据成员_Myptr
- _Tptr是如下,对于当前来讲就是int*
- 断点位置:
- v.begin()实际上就是将第一个元素的指针位置赋值给迭代器当中的指针类型
- go进去,调用了迭代器实际类型的构造函数,iterator实际类型是Vector_iterator,接着会调用基类的构造函数_Mybase
- _Mybase就是_Vector_const_iterator
- 接着F11,调用基类的构造函数。
_Pvector就是this指针,指向向量对象v - 接着调用Adopt函数(派生类没有实现Adopt方法,就会调用基类的Adopt方法)
_Vector_const_iterator继承至Ranit(表明他是一个随机迭代器),随机迭代器持有的类型_Ty,_Alloc::difference_type(表示两个元素之间差的类型,可正可负),const_pointer指针类型,const_conference引用类型。 - go进去,看下_Ranint是什么样的类,这种类没有什么有效代码,这种类仅仅是起到标识的作用;
但是它又继承至_Iterator_with_base - 继续go,_Iterator_with_base也是一个标识类,但是它又继承至_Base_class
- 继续go,
- 在这个类中提供了_Adopt方法,作用将容器类型_Parent保存到_Mycount中
- 最后,_Ptr初始化_Myptr,迭代器内部持有的一个指针类型,对于vector来讲,就是持有了int*类型
- 构造一个end()迭代器,将_Mylast传递进去,将_Mylast指针放到iterator当中的一个数据成员当中。
- 断点位置:
- 调用了迭代器it的!=号运算符,调用了==号运算符
!=是_Vector_const_iterator中的不等号运算符
判断迭代器所持有的指针是否等于传递进来的对象的指针。若相等,则说明这俩迭代器的是一样。 - 断点位置:
这里的this指针是iterator类型的指针,this是iterator *,_Mybase *就是_Vector_const_iterator *,
再说这里2个**问题,取后面的第一个*,得到的是_Vector_const_iterator ,再取前一个*,就是调用了_Vector_const_iterator 中的*号运算符
继续F11,继续到_Vector_const_iterator 中的*号运算符
实际上这个*号操作就是返回_Myptr取*号,对于当前来说,就是int*然后取*号,就是int类型,就是元素值;
这里的reference就是int类型的引用,返回的是一个引用
- 继续F11,位置
这里是前置++操作,而后置++操作会多一项临时对象的构造(注意返回的是对象,而不是引用,这里的++会调用前置的++),所以前置效率高一些;
(_Mybase *)this是_Vector_const_iterator *,
取*后,就是_Vector_const_iterator
继续F11,可以看到,调用的是_Vector_const_iterator 的++操作,最后返回的是对象自身的引用
- 总结:
iterator实际上借助const_iterator来实现,用继承方式来实现,所以不能将其看成是适配器。
适配器指的是通过模板作为类型参数传递的方式来实现的,eg:反向迭代器reverse_iterator
4.反向迭代器
- 反向迭代器是以适配器的方式来实现的,说明可以将正向迭代器传递进去来实现,使用正向迭代器来实现反向迭代器的相关功能
- eg:P77\02.cpp
与正向迭代器的begin,end的区别与联系
rend()指向第一个元素的前一个位置
- 断点位置
利用正向迭代器来实现反向迭代器,反向迭代器持有一个正向迭代器的成员
构造一个反向迭代器
reverse_iterator 的类型是typedef,通过将iterator传递到reverse_iterator 适配器中
reverse_iterator 又继承至反向随机迭代器_Revranit
继续F11,会调用其基类的构造函数
它持有了一个正向迭代器的成员,要构造_Revranit,先要构造其对象成员,所以会调用正向迭代器的构造函数,即_Vector_iterator
继续F11,会调用_Vector_iterator的构造函数
继续F11,_Vector_iterator继承至_Vector_const_iterator,所以会进入到_Vector_const_iterator构造函数中
- 断点:
利用正向迭代器的end()来实现反向迭代器rbegin;
rbegin()是end()之前的一个位置;
F11,调用基类
F11,继续调用基类,将正向迭代器传递给current
rend()不再跟踪
- 断点
看一下!=运算符
!=运算符重载了函数模板
F11
F11,调用_Equal方法
F11,返回current
继续F11,会调用_Vector_const_iterator中的==运算符,因为是调用了正向迭代器来实现的
继续F11
继续F11
- 断点:
rbegin()借助end()来实现,指向前一个;
rend()借助begin()来实现,也指向前一个;
关键在于*运算符的重载;
首先保存正向迭代器current(因为所借助的正向迭代器本身是不能改变的),然后–,再做一个取*操作
F11,–操作借助正向迭代器来实现
_Vector_iterator常量迭代器继承至_Vector_const_iterator常量迭代器,(_Mybase *)this所以先转为_Vector_const_iterator *,然后取*,就是_Vector_const_iterator ,–就是调用_Vector_const_iterator 的–运算符
继续F11,
(_Mybase *) this所以先转为_Vector_const_iterator *,*(_Mybase *)this就是_Vector_const_iterator ,**(_Mybase *)this就是调用_Vector_const_iterator 中的*运算符
F11,所以最终调用的是_Vector_const_iterator 来实现的
- 迭代器的实现原理总结:
反向迭代器以适配器的方式来实现,借助正向迭代器来实现;而普通正向迭代器又借助_Vector_const_iterator 来实现,实际上就是重载指针运算符,++运算符来实现的;
每一种类型都有自己的迭代器,每一种类型的迭代器内部实现方式可能不一样,vector仅仅是持有相应元素类型的指针,对指针进行操作; - eg:
- 断点位置:
F11,调用它的构造函数
F11
- 断点位置:
F11,链表的结构就是_Nodeptr
F11
F11
F11,链表最关键的地方就是++
F11
F11,_Nextnode()求出当前节点的下一个节点
- 总结
每一种容器的类型都有自己迭代器的实现方式,不同类型,其数据组织方式是不同的。
所以应该有不同的迭代器,来确定其是如何遍历的。
链表list由next的方式来遍历,向量vector按照位置来遍历
4.容器常用的成员
- 容器成员1
- size_type是无符号整数;
difference_type是整数;
iterator,迭代器,就是一个泛型指针,相当于原始类型的指针
关联式容器内部的数据是自动排序的,需要key_compare - 容器成员2
- map,set容器也支持下标[]运算;
at()较与[],支持测试是否越界; - 容器成员3
- 容器成员4
- 容器成员5
- 容器成员6,关联操作的只适用于关联式容器
- 参考:从零开始学C++之STL(三):迭代器类vector::iterator 和 vector::reverse_iterator 的实现、迭代器类型、常用的容器成员