SGI STL 迭代器解析

整理至侯捷《STL源码剖析》
迭代器是一种设计模式,现在编程语言基本都语言层面支持了这种模式,定义如下:提供一种方法,使之能遍历聚合物(容器)中的各个元素,而又不暴露聚合物内部的实现细节。
在STL中,迭代器在容器和算法之间扮演着桥梁的作用,算法通过迭代器访问容器中的数据。迭代器要实现下面几个功能:

  • 迭代器是一种智能指针
  • 迭代器要实现相应型别
萃取机制

由于算法中可能要用到用迭代器所指对象的类型来声明一个变量,这个时候该怎么办?注意C++中RTTI中的typeid()只能获得类型名称,不能用来做变量声明用。为此STL中实现了萃取机制。

  • 利用函数模板的参数推导机制
    下面代码中,func对外提供接口,实现放在func_impl中,首先func是个函数模板,编译器能够自动推导出 I 的类型,则迭代器iter类型和iter所指之物的类型都知道了,然后在func里以参数iter和*iter调用func_impl,由于func_impl也是模板函数,则,T的类型能推导出来,T temp 就是用迭代器所指之物类型来定义的变量tmp。
template <class I, class T>
void func_impl(I iter, T t)
{
    T tmp;
    //...
}

template <class I>
inline void func(I iter)
{
    func_impl(iter, *iter);
}

int main()
{
    int i;
    func(&i);
}
  • 内嵌类型
    注意上面的机制虽然能推导迭代器的所指之物类型即值类型(value type),但是如果value type要用于函数的返回值,比如上面代码中func函数要返回value type类型的返回值,则无法实现,由于函数模板的参数推导机制推导的是函数参数,无法推导返回值类型。
    内嵌类型可以解决返回值的问题。如下面代码中,我们将迭代器封装成一个类模板,在类模板中typedef T value_type;然后将func的返回值声明I::value_type,注意value_type前面要加上typename,告诉编译器这是一个型别,不然编译不过。这样在,迭代器类模板实例化模板类时,内嵌的value_type类型就能够自动推导出来,则可以用于func函数返回值的类型定义。
template <class T>
struct MyIter {
    typedef T value_type; //内嵌类型声明
    T *ptr;
    MyIter(T *p=0) : ptr(p) {}
    T& operator*() const { return *ptr; }
    //...
};

template <class I>
typename I::value_type
func(I ite)
{ return *ite; }

//...
MyIter<int> ite(new int(8));
cout << func(itr);
  • 偏特化
    上面的实现还有一个问题,STL中支持原生指针作为一种迭代器,然而其不是类类型,不能再起内部定义内嵌类型。所以要进行偏特化处理。偏特化定义:针对(任何)模板参数更进一步的条件限制所设计出来的一个特化版本。
    有了偏特化的方法则可以解决原生指针的问题。
    下面的类模板专门iterator_traits用来萃取迭代器的类型,如果 I 中定义有自己的value type那么就能够推导出value_type类型。
template <class I>
struct iterator_traits {
    typedef typename I::value_type value_type;
};

template <class T>
typename iterator_traits<I>::value_type 
func(I ite)
{ return *ite; }

下面对于原生指针实现偏特化版本

template <class T>
struct iterator_traits<T*> //指向指针的偏特化版
{
    typedef T value_type;
}

template <class T>
struct iterator_traits<const T*> //指向常数对象的指针的偏特化版
{
    typedef T value_type;
}

这里写图片描述
STL中常用的迭代器相应型别:value_type,difference_type,pointer,reference,iterator_category。

template <class _Iterator>
struct iterator_traits { //类模板中内嵌型别定义
  typedef typename _Iterator::iterator_category iterator_category;
  typedef typename _Iterator::value_type        value_type;
  typedef typename _Iterator::difference_type   difference_type;
  typedef typename _Iterator::pointer           pointer;
  typedef typename _Iterator::reference         reference;
};

template <class _Tp>
struct iterator_traits<_Tp*> { //指针特化版
  typedef random_access_iterator_tag iterator_category;
  typedef _Tp                         value_type;
  typedef ptrdiff_t                   difference_type;
  typedef _Tp*                        pointer;
  typedef _Tp&                        reference;
};

template <class _Tp>
struct iterator_traits<const _Tp*> { //指针常量特化版
  typedef random_access_iterator_tag iterator_category;
  typedef _Tp                         value_type;
  typedef ptrdiff_t                   difference_type;
  typedef const _Tp*                  pointer;
  typedef const _Tp&                  reference;
};

前面四个型别都较简单,下面分析下iterator_category:
根据移动特性,迭代器可以分为5种:
Input Iterator:输入型迭代器,只读;
Output Iterator:输出型迭代器,只写;
Forward Iterator:单向迭代器,单向读写;
Bidirectional Iterator:双向迭代器,双向读写;
Random Acess Iterator:随机访问迭代器,随机读写;
这里写图片描述
注意这里不是继承关系,而是概念与强化关系。STL在设计时,效率一直是首位,如果某个算法可接受Forward Iterator,而给它一个Random Acess Iterator,可以使用,但效率不一定是最佳的。所以要萃取出迭代器的种类。
以advanced()为例:

template <class _InputIter, class _Distance>
inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {
  while (__n--) ++__i;
}
template <class _BidirectionalIterator, class _Distance>
inline void __advance(_BidirectionalIterator& __i, _Distance __n, 
                      bidirectional_iterator_tag) {
  if (__n >= 0)
    while (__n--) ++__i;
  else
    while (__n++) --__i;
}
template <class _RandomAccessIterator, class _Distance>
inline void __advance(_RandomAccessIterator& __i, _Distance __n, 
                      random_access_iterator_tag) {
  __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
  __i += __n;
}
template <class _InputIterator, class _Distance>
inline void advance(_InputIterator& __i, _Distance __n) {
  __advance(__i, __n, iterator_category(__i));
}

__advance(_InputIter& __i, _Distance __n, input_iterator_tag);
__advance(_BidirectionalIterator& __i, _Distance __n, bidirectional_iterator_tag);
__advance(_RandomAccessIterator& __i, _Distance __n,random_access_iterator_tag);
上面三组模板函数构成重载函数,注意这里前两个参数都为模板参数,在运行时才能决定,不能构成重载机制,所以添加第三个参数来构成重载机制。

struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

只需要类型定义,只为了激活重载机制,构成继承关系只为消除单纯的传递调用。
对外提供advance(_InputIterator& __i, _Distance __n)接口,接受迭代器参数和偏移量参数,然后转调用__advance(__i, __n, iterator_category(__i)),通过iterator_category(__i)萃取出迭代器类型从而调用不同的重载模板函数。
iterator_category(__i)又调用了内部函数__iterator_category(__i)。

template <class _Iter>
inline typename iterator_traits<_Iter>::iterator_category
iterator_category(const _Iter& __i) { return __iterator_category(__i); }

__iterator_category(__i)中真正通过iterator_traits萃取出迭代器型别。

template <class _Iter>
inline typename iterator_traits<_Iter>::iterator_category
__iterator_category(const _Iter&)
{
  typedef typename iterator_traits<_Iter>::iterator_category _Category;
  return _Category();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值