【C++ STL学习】容器迭代器 iterator详解

内容及源码参考自《The Annotated STL Sources》

目录

1. 本质

2. 分类

3. 操作

4. 各容器的迭代器


1. 本质

要访问顺序容器和关联容器中的元素,需要通过“迭代器(iterator)”进行。迭代器是一个变量,相当于容器和操纵容器的算法之间的中介。迭代器可以指向容器中的某个元素,通过迭代器就可以读写它指向的元素。从这一点上看,迭代器和指针类似。

 

2. 分类

1) 正向迭代器,定义方法如下:

容器类名::iterator  迭代器名;

2) 常量正向迭代器,定义方法如下:

容器类名::const_iterator  迭代器名;

3) 反向迭代器,定义方法如下:

容器类名::reverse_iterator  迭代器名;

4) 常量反向迭代器,定义方法如下:

容器类名::const_reverse_iterator  迭代器名;

5)随机访问迭代器

随机访问迭代器具有双向迭代器的全部功能。若 p 是一个随机访问迭代器,i 是一个整型变量或常量,则 p 还支持以下操作:

p+=i //使得 p 往后移动 i 个元素。
p-=i //使得 p 往前移动 i 个元素。
p+i  //返回 p 后面第 i 个元素的迭代器。
p-i  //返回 p 前面第 i 个元素的迭代器。
p[i] //返回 p 后面第 i 个元素的引用。

 

3. 操作

*  //读取、修改迭代器指向的元素
++ //正向迭代器:迭代器会指向容器中的后一个元素
   //反向迭代器:迭代器会指向容器中的前一个元素
== //比较
!= //比较

 

4. 各容器的迭代器

STL类型迭代器类型insert,splice,erase操作对迭代器的影响
vector 随机访问

一旦出现内存重新分配,则导致原有迭代器全部失效。

deque 随机访问
list环状双向链表双向

不会导致原有迭代器全部失效。

erase也只导致"指向被删除元素"的那个迭代器失效,其他迭代器不受影响。

set / multiset 双向
map / multimap 双向
stack 不支持迭代器 
queue 不支持迭代器
priority_queue 不支持迭代器

(1)vector 的迭代器是随机迭代器(Random Access Iterator)

  • 因为元素在存储空间中连续存在,故实际是普通指针
 iterator start;  //表示目前使用空间的头
 iterator finish; //表示目前使用空间的尾
 iterator end_of_storage; //表示目前可用空间的尾
  • 遍历 vector 容器
#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int> v(100); //v被初始化成有100个元素
    for(int i = 0;i < v.size() ; ++i) 
        cout << v[i]; //像普通数组一样使用vector容器
    vector<int>::iterator i;
    for(i = v.begin(); i != v.end (); ++i) //用 != 比较两个迭代器
        cout << * i;
    for(i = v.begin(); i < v.end ();++i) //用 < 比较两个迭代器
        cout << * i;
    i = v.begin();
    while(i < v.end()) { //间隔一个输出
        cout << * i;
        i += 2; // 随机访问迭代器支持 "+= 整数"  的操作
    }
}

(2)list的迭代器是双向迭代器(Bidirectional Iterator)

  • 元素在存储空间中非连续存在,需要记录每一个节点的指针,保证insert和splice都不会造成原有的iterator失效
template<class T, class Ref, class Ptr> 
struct__list_iterator { 
 typedef __list_iterator<T, T&, T*> iterator; 
 typedef __list_iterator<T, Ref, Ptr> self; 
 typedef bidirectional_iterator_tag iterator_category; 
 typedef Tvalue_type; 
 typedef Ptrpointer; 
 typedef Refreference; 
 typedef__list_node<T>* link_type; 
 typedef size_t size_type; 
 typedef ptrdiff_tdifference_type; 

 link_typenode; //迭代器内部当然要有一个原生指标,指向 list 的节点

// constructor 
 __list_iterator(link_type x) : node(x) {} 
 __list_iterator() {} 
 __list_iterator(const iterator& x) : node(x.node) {} 

 bool operator==(const self& x) const { return node == x.node; } 
 bool operator!=(const self& x) const { return node != x.node; }
 
// 以下对迭代器取值(dereference),取的是节点的资料值。
 referenceoperator*() const { return (*node).data; } 

// 以下是迭代器的成员存取(member access)运算子的标准作法。
 pointeroperator->() const { return &(operator*()); } 
// 对迭代器累加 1,就是前进一个节点
 self& operator++()    //++p
     node = (link_type)((*node).next); 
     return *this; 
 } 
 self operator++(int)  //p++ p.s.为了重载可区分前、后缀,其中一个函数参数可增加1,一般后缀增1个int型参数。
     self tmp = *this; 

     ++*this; 
     return tmp; 
 } 
// 对迭代器递减 1,就是后退一个节点
 self& operator--()    //--p
     node = (link_type)((*node).prev); 
     return *this; 
 } 
 self operator--(int)  //p--
     self tmp = *this; 
     --*this; 
     return tmp; 
 } 
};
  • 遍历list 容器
for(i=v.begin(); i!=v.end(); ++i) //合法
    cout << *i;

for(i=v.begin(); i<v.end(); ++i)  //不合法
    cout << *i;

for(int i=0; i<v.size(); ++i)     //不合法
    cout << v[i];

(3)deque的迭代器

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值