C++STL 体系结构与内核分析(侯捷)——课程笔记(十一)

现在开始了算法的讲解。本部分包括迭代器的类型以及其对算法的影响,还包括一点traits的内容。

STL中的Algorithms对Containers一无所知,所以它需要的一切信息都必须从Iterators取得,而Iterators必须能够回答Algorithms的所有提问,才能搭配Algorithms的所有操作。

一、iterators的各种iterator_category

一共有五种iterator_category,每种category都是一个class,并且它们之间还存在一些继承关系,如下图所示:

(注意图里面forward写错了)

forward_iterator_tag、bidirectional_iterator_tag、random_access_iterator_tag不用说了,比较特殊的是input_iterator_tag和output_iterator_tag,istream_iterator的iterator_category是input_iterator_tag,ostream_iterator的iterator_category是output_iterator_tag,这两个并不属于容器的迭代器,特别是output_iterator_tag还有“只写”的特殊行为。

二、iterator_category对算法的影响

1. 根据iterator_category的不同,调用不同版本的处理函数,下面举两个例子:

(1) distance()函数用来求解两个迭代器之间的距离。所以当迭代器是随机访问迭代器时,距离可以直接相减得到,其他情况需要依次遍历。

template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last){
    typedef typename
        iterator_traits<InputIterator>::iterator_category category;
    return __distance(first, last, category());
}

template <class RandomAccessIterator>
inline iterator_traits<RandomAccessIterator>::difference_type
__distance(RandomAccessIterator first, RandomAccessIterator last,
           random_access_iterator_tag){
    return last - first;
}

template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
__distance(InputIterator first, InputIterator last,
           input_iterator_tag){
    iterator_traits<InputIterator>::difference_type n = 0;
    while(first != last){
        ++first; ++n;
    }
}

(2) advance()函数将一个迭代器向前移动n步,如果是随机访问迭代器可以直接得到,如果是双向迭代器还要注意n的正负代表了移动的方向。

template <class InputIterator, class Distance>
inline void advance(InputIterator& i, Distance n){
    __advance(i, n, iterator_category(i));
}

template <class Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&){
    typedef typename iterator_traits<Iterator>::iterator_category category;
    return category();
}

template <class RandomAccessIterator, class Distance>
inline void __advance(RandomAccessIterator& i, Distance n,
                      random_access_iterator_tag){
    i += n;
}

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 InputIterator, class Distance>
inline void __advance(InputIterator& i, Distance n,
                      input_iterator_tag){
    while(n--) ++i;
}

三、iterator_category和type traits对算法的影响

1. copy(first, last, destination_start)函数

(1) 先对copy()函数定义重载版本,如果传入的类型为某些特定类型(如图所示),就调用较快的C的库函数。

(2) 对传入的迭代器也要进行一些判断,通过iterator traits分辨出作为class的迭代器和普通指针,如果是作为class的迭代器,通过iterator_category判断是否为随机访问迭代器,如果是的话就可以优化copy动作(用n决定循环次数),如果不是,就要使用迭代器作为循环变量进行拷贝。

(3) 在(2)中如果iterator_traits分辨出的是普通指针,那么就要通过type traits判断指针指向的对象有没有non-trival的拷贝赋值运算符,如果没有说明对象是基本类型或者是由基本类型组成的简单class,就会调用C的库函数;如果有的话,就需要迭代进行拷贝赋值操作,当然可以用n作为循环变量,因为迭代器是普通指针。

2. destroy()函数

分析过程与1类似,不再详述

3. __unique_copy()对于output_iterator_tag的特殊处理

因为output_iterator_tag是只能写的,不能读取,所以要针对这个版本做特殊处理

最后还有一个小tips,叫做算法源码中对iterator_category的暗示,这是指可能有某些函数只能接受某些类型的迭代器,就比如说sort()只接受随机访问迭代器,但是在语法上(函数模板的语法)不禁止传入其他类型的迭代器,但是在源码中会把模板参数的名字命名为相应的迭代器类型,起到提醒使用者的目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值