迭代器:就是提供一种方法,在不需要暴露某个容器的内部表现形式情况下,使之能依次访问该容器中的各个元素。
STL的中心思想在于:将数据容器(containers)和算法(algorithms)分开,彼此独立设计,最后再以一帖粘合剂将它们撮合在一起。只要对算法给予不同的迭代器,就可以对不同容器进行相同的操作。
以算法find( )为例,它接受2个迭代器和1个”搜寻目标”:
// 摘自SGI <stl_algo.h>
template <class InputIterator, class T>
InputIterator find(InputIterator first,InputIterator last,const T& value)
{
while (first != last && *first != value)
++first;
return first;
}
只要给予不同的迭代器,find()便能够对不同的容器进行查找操作:
#include <vector>
#include <list>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
const int arraySize = 7;
int ia[arraySize] = { 0,1,2,3,4,5,6 };
vector<int> ivect(ia, ia+arraySize);
list<int> ilist(ia, ia+arraySize);
deque<int> ideque(ia, ia+arraySize);
vector<int>::iterator it1 = find(ivect.begin(), ivect.end(), 4);
if (it1 == ivect.end())
cout << "4 not found." << endl;
else // 結果:4 found. 4
cout << "4 found. " << *it1 << endl;
list<int>::iterator it2 = find(ilist.begin(), ilist.end(), 6);
if (it2 == ilist.end())
cout << "6 not found." << endl;
else// 結果:6 found. 6
cout << "6 found. " << *it2 << endl;
deque<int>::iterator it3 = find(ideque.begin(), ideque.end(), 8);
if (it3 == ideque.end())
cout << "8 not found." << endl;
else// 結果:8 not found.
cout << "8 found. " << *it3 << endl;
return 0;
}
迭代器是一种行为类似指针的对象,而指针的各种行为中最常见也最重要的便是内容提领(dereference)和成员访问(member access),因此,迭代器最重要的编程工作就是对 operator*
和 operator->
进行重载(overloading)工作。
使得所有实现细节得以封装起来,不被使用者看到,是每一种STL容器都提供有专属迭代器的缘故。
迭代器所指对象的型别,称为迭代器的value type。
我们知道:
(1)通过函数模板的参数类型推导解决函数体内声明变量的问题
(2)进一步,函数模板的参数类型推导推而导之的只是参数,无法推导函数的返回值型别。这时,如果需要返回类型是迭代器所指对象的类型,解决办法就是内嵌类型声明,即在迭代器内部添加一种“特性”,通过这种“特性”,算法可以很容易地获知迭代器所指对象的类型。
但是,问题来了,并不是所有迭代器都是class type。原生指针是迭代器,但它不是一种类类型,无法定义内嵌类型。怎么办?针对原生指针做特殊化的处理,利用模板偏特化就可以做到了。
利用模板偏特化解决原生指针不能内嵌类型的问题,iterator_traits就是关键。
在STL实现中,traits编程技术利用了“内嵌类型”的编程技巧与C++的template参数推导功能,弥补了C++类型识别方面的不足。通过traits,算法可以原汁原味的将迭代器的属性萃取出来,帮助算法正确高效的运行。
所谓traits,其意义是,如果template <class I>
中的I定义有自己的value type,那么通过这个traits的作用,萃取出来的value_type就是I::value_type
。traits就像一台”特性萃取机”,萃取出各个迭代器的特性。
最常用到的迭代器相应型别有五类:value type, difference type, pointer, reference, iterator catagoly
。
STL提供的iterator class如下。它不含任何成员,纯粹只是型别定义。
template <class Category,
class T,
class Distance = ptrdiff_t,
class Pointer = T*,
class Reference = T&>
struct iterator {
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
};
特性萃取机traits会很原汁原味的榨取出来:
template <class I>
struct iterator_traits {
typedef typename I::iterator_category iterator_category;
typedef typename I::value_type value_type;
typedef typename I::difference_type difference_type;
typedef typename I::pointer pointer;
typedef typename I::reference reference;
};
这些类型所表示的意义如下:
value type 表示迭代器所指对象的型别;
difference type 表示两个迭代器之间的距离;也可表示一个容器最大容量
reference 为引用类型;
pointer 为指针类型;
iterator_category 表明迭代器的类型;
根据迭代器移动特性与施行动作,迭代器被分为五类:
1、Input Iterator:这种迭代器所指对象,不允许外界改变,只读(read
only);
2、Output Iterator:唯写(write only);
3、Forward Iterator:允许「写入型」算法(例如 replace())在此种迭
代器所形成的区间上做读写动作;
4、Bidirectional Iterator:可双向移动。某些算法需要逆向走访某个迭
代器区间(例如逆向拷贝某范围内的元素),就可以使用 Bidirectional
Iterators;
5、Random Access Iterator:前四种迭代器都只供应一部份指标算术能力
(前3种支持 operator++ ,第4种再加上 operator--),第5种则涵盖所
有指标算术能力,包括 p+n, p-n, p[n], p1-p2, p1<p2.