现在开始了算法的讲解。本部分包括迭代器的类型以及其对算法的影响,还包括一点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()只接受随机访问迭代器,但是在语法上(函数模板的语法)不禁止传入其他类型的迭代器,但是在源码中会把模板参数的名字命名为相应的迭代器类型,起到提醒使用者的目的。