《STL源码剖析》学习笔记-第3章 迭代器

1、迭代器设计思维-STL关键所在

迭代器:就是提供一种方法,在不需要暴露某个容器的内部表现形式情况下,使之能依次访问该容器中的各个元素。

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;
}

2、迭代器是一种智能指针

迭代器是一种行为类似指针的对象,而指针的各种行为中最常见也最重要的便是内容提领(dereference)和成员访问(member access),因此,迭代器最重要的编程工作就是对 operator*operator-> 进行重载(overloading)工作。

使得所有实现细节得以封装起来,不被使用者看到,是每一种STL容器都提供有专属迭代器的缘故。

3、Traits编程技法——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就像一台”特性萃取机”,萃取出各个迭代器的特性。

4、迭代器基本框架

最常用到的迭代器相应型别有五类: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);
3Forward 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.

你可能感兴趣的:(迭代器,STL)