内容及源码参考自《The Annotated STL Sources》
目录
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的迭代器