STL源码:迭代器萃取器

Iterator traits

迭代器类别详解

迭代器有5中类别,如下图:

在这里插入图片描述

这里的关系并不是继承,而是强化。比如一个算法可以接受 Random Access Iterator,那么它也能接受 Forward Iterator,反之不然。
一个迭起器,应当落在能支持的最强化的哪一个,如 int* 可以被归入多个,它将选择最强的 Random Access Iterator

以 advance() 为例子,它定义了3个版本,分别是 Input Iterator,Bidirectional Iterator 和 Random Access Iterator,分别支持 单向逐一前进(迭代器只能++,不能+n),双向逐一前进,双向跳跃前进

当调用advance()时,如果选择 Input Iterator,对于 Random Access Iterator 而言遍历复杂度从 O(1) 变成 O(n)
如果选择 Random Access Iterator,则无法接受 Input Iterator

一种简单的方法,在advance()内部对迭代器类型进行 if-else 判断,但这样在执行期间才能判断使用哪一个版本,缺乏效率
更好的方法是在编译期间就确定下来:给advance添加第3个参数,形成重载函数

定义多个 _advance函数,例如 _advance(RandomAccessIterator& i, Distance n, random_access_iterator_tag)
注意最后一个参数只声明类型,没有参数名称,因为它只是用来激活函数,在函数实现中不会使用
最后,还还要一个上层接口 advance 和调用者对接,它只需要两个参数

//这里需要特别注意的是,STL算法的一个命名规则:以能接收的最低阶的迭代类型来为参数命名,因此这里是class InputIterator
template <class InputIterator, class Distance>
inline void advance(InputIterator& i, Distance n){
    return __advance(i, n, iterator_traits<InputIterator>::iterator_category());
}

因此,iterator需要定义一个类型,即 iterator_category

传递调用

distance()和advance()的设计如出一辙,它可以接收任何类型的迭代器。以它为例,当调用distance(),并使用 Output Iterator,Forward Iterator,Bidirectional Iterator时,由于继承关系的存在,统统都会传递调用 Input Iterator 那个版本的 __distance()函数

这是因为上层接口 distance() 中将以最低阶的 InputIterator 来接收所有类别参数,当调用 __distance发现这一参数和 iterator_traits中的 category不一样时,就会去调用父类的那一种实现

源码总览:stl_iterator_base_types

在 list 容器的源码中,可以看到 _List_iterator 中定义了如下内容:

template<typename _Tp>
struct _List_iterator {
	......
    typedef ptrdiff_t                          difference_type;
    typedef std::bidirectional_iterator_tag    iterator_category;
    typedef _Tp                                value_type;
    typedef _Tp*                               pointer;
    typedef _Tp&                               reference;
    ......
}

difference_type,iterator_category,value_type,pointer,reference是迭代器必要的5个属性,这些属性是萃取器的要求
在文件 bits/stl_iterator_base_types.h中,定义了迭代器的萃取器如下:

  • 主要是对5种迭代器类型和5种要萃取的特性的说明
  • 函数实现在stl_iterator_base_func.h文件当中
  • 运算符重载在stl_iterator.h文件当中
//表示只读迭代器
struct input_iterator_tag { };
//只写迭代器
struct output_iterator_tag { };
//允许“写入”型算法,如replace()
struct forward_iterator_tag : public input_iterator_tag { };
//可双向移动
struct bidirectional_iterator_tag : public forward_iterator_tag { };
//可随机访问,支持所有指针算术能力。前3种支持++,第4种再加上--
struct random_access_iterator_tag : public bidirectional_iterator_tag { };

/*
目的:iterator class不含任何成员,只是单纯的类别定义,如果每一个新设计的iterator都继承自它,就可以保证符合STL规范
想要适配地使用STL算法,那么迭代器一定要定义以下5种类型,后2个都有默认值,如需使用只需要给出 _Category 和 _Tp
list虽然没有继承,但也自行定义了这5个类型。自行开发的迭代器最好都继承自这个iterator classs
*/
template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t,
typename _Pointer = _Tp*, typename _Reference = _Tp&>
struct iterator {
    //1. 迭代器的类型,上面5种中的一个
    typedef _Category  iterator_category;
    //2. 迭代器所指对象的类型,例如list<int>l,那么value_type就是int的类型别名
    typedef _Tp        value_type;
    //3. 两个迭代器之间的举例,常用来表示一个容器的最大容量。如STL的count()就会使用到difference_type
    //ptrdiff_t是一种数据类型,用来保存两个指针减法操作的结果,常被定义为long int
    //当需要使用任何迭代器的difference_type,可以这样写:typename iterator_traits<I>::difference_type
    typedef _Distance  difference_type;
    //4. 同样以int为例,pointer就是 int*
    typedef _Pointer   pointer;
    //5. 类型引用,以int为例,就是 int&,使得
    typedef _Reference reference;
};

#if __cplusplus >= 201103L
//空模板
template<typename _Iterator, typename = __void_t<>>
struct __iterator_traits { };
//接收一个迭代器,将它的属性作为自己的属性(萃取)。_Iterator只声明类型,没有定义参数变量。
template<typename _Iterator>
struct __iterator_traits<_Iterator, __void_t<typename _Iterator::iterator_category,
                                            typename _Iterator::value_type,
                                            typename _Iterator::difference_type,
                                            typename _Iterator::pointer,
                                            typename _Iterator::reference>> {
    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;
};
//继承__iterator_traits
template<typename _Iterator>
struct iterator_traits : public __iterator_traits<_Iterator> { };
#else
//c++11之前的版本,直接定义
template<typename _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;
};
#endif

//针对原生指针的traits偏特化版,也就是迭代器不是一个类,而只是一个指针,这种情况需要特化一下
template<typename _Tp>
struct iterator_traits<_Tp*> {
    //注意在偏特化版本中,iterator_category的类型是random_access_iterator_tag
    typedef random_access_iterator_tag iterator_category;
    typedef _Tp                         value_type;
    typedef ptrdiff_t                   difference_type;
    typedef _Tp*                        pointer;
    typedef _Tp&                        reference;
};

//针对 const 修饰的原生指针的偏特化版本
template<typename _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;
};

//获取迭代器的类型
template<typename _Iter>
inline typename iterator_traits<_Iter>::iterator_category __iterator_category(const _Iter&) { 
    return typename iterator_traits<_Iter>::iterator_category(); 
}

//这里的_Iter_base很少被提及,作用不明
template<typename _Iterator, bool _HasBase>
struct _Iter_base {
    typedef _Iterator iterator_type;
    static iterator_type _S_base(_Iterator __it) { 
        return __it; 
    }
};
template<typename _Iterator>
struct _Iter_base<_Iterator, true> {
    typedef typename _Iterator::iterator_type iterator_type;
    static iterator_type _S_base(_Iterator __it) { 
        return __it.base(); 
    }
};

#if __cplusplus >= 201103L
//重载决议,详情见:https://www.zhihu.com/question/31491227?sort=created
template<typename _InIter>
using _RequireInputIter = typename
enable_if<is_convertible<typename iterator_traits<_InIter>::iterator_category,
											input_iterator_tag>::value>::type;
#endif

源码总览:stl_iterator_base_func

  • 主要是定义advance(),distance()等函数,注意其中用到的传递调用
namespace std _GLIBCXX_VISIBILITY(default) {
_GLIBCXX_BEGIN_NAMESPACE_VERSION
    /*
    函数:distance()
    __distance函数是distance的底层函数,根据迭代器的不同有多个重载版本。对于distance而言,只需要两个__advance版本
    在传递调用的作用下,除了RandomAccessIterator之外,其他的都和InputIterator操作相同,因此都调用input迭代器版本
    */
	//__distance函数, InputIterator版本
    template<typename _InputIterator>
    inline typename iterator_traits<_InputIterator>::difference_type
        __distance(_InputIterator __first, _InputIterator __last,
                   input_iterator_tag)
    {
        // concept requirements
        __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
		//计算distance
        typename iterator_traits<_InputIterator>::difference_type __n = 0;
        while (__first != __last) {
            ++__first;
            ++__n;
        }
        return __n;
    }
	//__distance函数, RandomAccessIterator版本,可以直接相减
    template<typename _RandomAccessIterator>
    inline typename iterator_traits<_RandomAccessIterator>::difference_type
        __distance(_RandomAccessIterator __first, _RandomAccessIterator __last,
                   random_access_iterator_tag)
    {
        // concept requirements
        __glibcxx_function_requires(_RandomAccessIteratorConcept< _RandomAccessIterator>)
        return __last - __first;
    }
    //distance的上层接口,只需要传入2个参数。按照STL规则,以最低阶的InputIterator接收参数
    template<typename _InputIterator>
    inline typename iterator_traits<_InputIterator>::difference_type
        distance(_InputIterator __first, _InputIterator __last)
    {
        return std::__distance(__first, __last, std::__iterator_category(__first));
    }
	
    /*
    函数:advance()
    有3个版本的__advance(),分别是InputIterator,BidirectionalIterator,RandomAccessIterator
    output迭代器,forward迭代器的__advane操作和input迭代器的操作相同,所以完全可以向上调用input迭代器的对应函数
    */
    //__advance()函数,只读版本
    template<typename _InputIterator, typename _Distance>
    inline void __advance(_InputIterator& __i, _Distance __n, input_iterator_tag) {
        // concept requirements
        __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
        _GLIBCXX_DEBUG_ASSERT(__n >= 0);
        while (__n--)
            ++__i;
    }
	//__advance()函数,双向版本,允许回退
    template<typename _BidirectionalIterator, typename _Distance>
    inline void __advance(_BidirectionalIterator& __i, _Distance __n, bidirectional_iterator_tag) {
        // concept requirements
        __glibcxx_function_requires(_BidirectionalIteratorConcept<_BidirectionalIterator>)
        if (__n > 0)
            while (__n--)
                ++__i;
        else
            while (__n++)
                --__i;
    }
	//__advance()函数,随机版本
    template<typename _RandomAccessIterator, typename _Distance>
    inline void __advance(_RandomAccessIterator& __i, _Distance __n, random_access_iterator_tag) {
        // concept requirements
        __glibcxx_function_requires(_RandomAccessIteratorConcept<_RandomAccessIterator>)
        __i += __n;
    }
  	//advance的上层接口
    template<typename _InputIterator, typename _Distance>
    inline void advance(_InputIterator& __i, _Distance __n) {
        // concept requirements -- taken care of in __advance
        typename iterator_traits<_InputIterator>::difference_type __d = __n;
        std::__advance(__i, __d, std::__iterator_category(__i));
    }

    #if __cplusplus >= 201103L
    //next的函数,前进n个,由advance实现,采用ForwardIterator,返回迭代器
    template<typename _ForwardIterator>
    inline _ForwardIterator next(_ForwardIterator __x, typename
                                 iterator_traits<_ForwardIterator>::difference_type __n = 1) {
        std::advance(__x, __n);
        return __x;
    }
	//prev函数,后退n个,由advance实现,采用BidirectionalIterator
    template<typename _BidirectionalIterator>
    inline _BidirectionalIterator prev(_BidirectionalIterator __x, 
					typename iterator_traits<_BidirectionalIterator>::difference_type __n = 1) {
        std::advance(__x, -__n);
        return __x;
    }
    #endif // C++11
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

其他知识:__type_traits(SGI STL)
将迭代器萃取扩展到其他类型,就有了type_traits,并相应地定义了true_type和false_type
type_traits可以萃取任意类型的特性

除了这两个文件之外,还有一个stl_iterator.h文件,主要定义了各种运算符重载,多且杂,以后有时间再仔细看
除此之外,还有type_traits,char_traits,alloc_traits等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值