STL与泛型编程<八>:迭代器简介

来源:互联网 发布:礼品定制 知乎 编辑:程序博客网 时间:2024/05/17 23:29

总述

迭代器是一种型别(通俗的讲就是以一种类)声明如下

template <class Category,              // iterator::iterator_category          class T,                     // iterator::value_type          class Distance = ptrdiff_t,  // iterator::difference_type          class Pointer = T*,          // iterator::pointer          class Reference = T&         // iterator::reference          > class iterator;

所有容器都定义其各自的迭代器型别(iterator types),所以不需要专门的头文件,但有的迭代器需要,如逆向迭代器,被定义在#include中,迭代器是一种“能够遍历某个序列内所有元素”的对象,它可以透过一般指针一致的接口来完成自己的工作。其主要分为以下几种,见图
这里写图片描述

input(输入)迭代器

input迭代器只能一次一个向前读取元素,按顺序一个个传回元素值。注意input迭代器只能读取元素一次,如果你复制了input迭代器,并使原input迭代器和新产生的副本都向前读取,可能会遍历到不同的值
几乎所有的迭代器都具有input迭代器的功能,一个典型的例子就是从“标准输入读取数据”,同一个值不会被读两次。常见操作见下图
这里写图片描述
注意input迭代器不提供递减运算操作符

output(输出)迭代器

output迭代器是将元素值一个个写入,也就是说,你只能一个个元素地赋新值,而且不能使用output迭代器对同一序列进行两次遍历,下图是其操作
这里写图片描述
operator/*只有在赋值语句左手边才有效,注意output迭代器无需比较,无法检验output迭代器是否写入成功,唯一可以做的就是写入,再写入,几乎所有迭代器都具有output迭代器的功能。一个典型的例子“将元素输出到标准输出设备”的迭代器;output迭代器另一个典型例子就是inserters,所谓inserters是用来将元素插入容器的一种迭代器。

forward(前向)迭代器

forward迭代器是input迭代器和output迭代器的结合,具有input迭代器的全部功能和output迭代器的部分功能,其操作如下图
这里写图片描述
为什么具有output迭代器的部分功能,见下
若是output迭代器,我们无需检查是否抵达序列尾端,便可直接写入数据,因此可以这样写

while (true){    *pos = foo();    ++pos;}

对于forward迭代器,必须在存取数据之前确保有效,否则会引发未定义的行为,因此得这么写

while (pos != col.end()){    *pos = foo();    ++pos;}

这个循环不适合output迭代器,因为output迭代器没有定义operator!=

bidirectional(双向)迭代器

双向迭代器在forward迭代器的基础上提供了回头遍历的能力,换言之,它支持递减运算符,其新增操作如下
这里写图片描述
- random access(随机存取)迭代器
random access迭代器在双向迭代器的基础上再增加随机存取能力,因此它必须提供“迭代器算术运算”,也就是说它能够加减某个偏移量,能处理距离问题,并运用比较操作符,以下迭代器支持rand access迭代器:
1. 可随机存取的迭代器(vector,deque)
2. string(字符串,string,wstring)
3. 一般array(指针)
其新增的操作如下图
这里写图片描述
见一个例子

#include <iostream>#include <vector>using namespace std;int main(void){    vector<int> col;    for (int i=-3; i<=9; ++i)        col.push_back(i);    //只适用于随机迭代器    cout << "number/distance: " << col.end() - col.begin() << endl;    vector<int>::iterator pos;    for (pos=col.begin(); pos!=col.end(); ++pos)        cout << *pos << ' ';    cout << endl;    //此操作只对random access 有效    for (int i=0; i<col.size(); ++i)        cout << col.begin()[i] << ' ';    cout << endl;    //此操作只对random access 有效    for (pos=col.begin(); pos < col.end()-1; pos+=2)  //注意这里的循环结束条件(避免未定义行为)        cout << *pos << ' ';    cout << endl;    return 0; } 

本例对lists,sets和maps无效,因为程序中标识的部分都只适用于random access迭代器。注意只有在面对random access迭代器时,才能以operator< 作为结束与否的判断准则
对于程序中最后一个循环的解释见下图
这里写图片描述

容器的迭代器类型

  1. vector和deque的迭代器是随机迭代器,灵活性最大,基本适用于任何一个STL算法及迭代器相关操作
  2. list的迭代器是双向迭代器,因此凡是用到随机迭代器的STL算法你都不能使用
  3. set和map的迭代器也是双向迭代器
1 0