STL学习笔记之迭代器--iterator(源码剖析)

来源:互联网 发布:centos 配置smtp 编辑:程序博客网 时间:2024/05/22 03:11

迭代器(iterator)是STL里面很基础也很重要的一个东西,迭代器的traits技术设计的很棒(在上一篇文章《STL笔记之空间配置器》中提到destroy函数使用了traits技术来判断对象是否具有trivial destructor,然后通过重载自动选择合适的实现版本)。

迭代器是一种行为类似指针的对象,因为指针最常用的是->和*两个操作符,因此迭代器最重要的编程工作也是对这两个操作符的重载的实现。

1. 初探traits技术
假设现在定义了这样一个迭代器MyIter,当我们拿到一个MyIter对象时,如何判断他的类型呢?

template<class T>struct MyIter{    T* ptr;    MyIter(T* p=0) : ptr(p) {}    T& operator*() const { return *ptr; }}; MyIter<int> iter(new int(1)); // What's type of *iter ???
在STL的实现中,给MyIter添加了一个value_type的定义,然后通过MyIter::value_type取得对应的类型,这就是所谓的traits技术了。

#include <iostream>using namespace std; template<class T>struct MyIter{    typedef T value_type;  // value_type定义    T* ptr;    MyIter(T* p=0) : ptr(p) {}    T& operator*() const { return *ptr; }}; template<class I>typename I::value_type     // typename用于指明I::value_type是个类型func(I ite){    return *ite;} int main(int argc, char **argv){    MyIter<int> ite(new int(8));    cout << func(ite) << endl;     return 0;}// 输出8

上面的代码中通过模板参数的value_type来推导出具体的类型,注意typename用于指明I::value_type是个类型,如果没有typename的话,编译器将把value_type当成I的一个member或者member function。

问题:既然说迭代器是一种智能指针,那么func对于普通的原始指针也应该是可用的,但是普通的原始指针不是对象,并不不具备value_type这内嵌个类型的定义,解决之道就是使用偏特化技术(partial specialization)。

2. 模板特化
C++模板的分两种:偏特化和全特化(所谓偏特化是指部分特化)。
特化(或者说全特化,specialized)不过是一个花哨的术语,意思是形参不再为形参,它们已经有了确定的值;而偏特化(partial specialization)的意思是提供另一份template的定义,其本身仍然是一个template,或者说针对template参数更进一步的条件限制所设计出来的一个特化版本。

#include <iostream>using namespace std; // traits模板的定义template<class I>struct my_traits{    typedef typename I::value_type value_type;}; // 针对T*的偏特化版本template<class T>struct my_traits<T*>{    typedef T value_type;}; // 针对const T*的偏特化版本template<class T>struct my_traits<const T*>{    typedef T value_type;}; // MyIter定义template<class T>struct MyIter{    typedef T value_type;    T* ptr;    MyIter(T* p=0) : ptr(p) {}    T& operator*() const { return *ptr; }}; // func函数模板,注意返回类型为typename my_traits<I>::value_typetemplate<class I>typename my_traits<I>::value_typefunc(I ite){    return *ite;} int main(int argc, char **argv){    MyIter<int> ite(new int(8));    cout << func(ite) << endl;     int *p = new int(1);    const int *pc = new int(2);    cout << func(p) << endl;    cout << func(pc) << endl;     return 0;}// 输出8 1 2

经过添加模板偏特化版本的定义之后,func对于原始指针也可以支持了。本文重点描述迭代器相关特性,所以关于特化的更多介绍,请自行搜索相关资料。

3. 迭代器基本框架
按照约定,迭代器需要定义5个内嵌类型:iterator_category、value_type、difference_type、pointer、reference

#include <iostream>using namespace std; // traits模板的定义template<class I>struct my_traits{    typedef typename I::value_type value_type;}; // 针对T*的偏特化版本template<class T>struct my_traits<T*>{    typedef T value_type;}; // 针对const T*的偏特化版本template<class T>struct my_traits<const T*>{    typedef T value_type;}; // MyIter定义template<class T>struct MyIter{    typedef T value_type;    T* ptr;    MyIter(T* p=0) : ptr(p) {}    T& operator*() const { return *ptr; }}; // func函数模板,注意返回类型为typename my_traits<I>::value_typetemplate<class I>typename my_traits<I>::value_typefunc(I ite){    return *ite;} int main(int argc, char **argv){    MyIter<int> ite(new int(8));    cout << func(ite) << endl;     int *p = new int(1);    const int *pc = new int(2);    cout << func(p) << endl;    cout << func(pc) << endl;     return 0;}// 输出8 1 2

这些类型所表示的意义如下:
value type 用来表示迭代器所指对象的型别;
difference type 用来表示两个迭代器之间的距离;
reference 为引用类型;
pointer 为指针类型;
iterator_category 表明迭代器的类型;

根据迭代器移动特性与施行动作,迭代器被分为五类:
1. Input Iterator:这种迭代器所指对象,不允许外界改变,只读(read only);
2. Output Iterator:唯写(write only);
3. Forward 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 ;<="" p="">

几种迭代器之间的关系图:
STL迭代器类型关系图

4. iterator源码

#ifndef __SGI_STL_INTERNAL_ITERATOR_BASE_H#define __SGI_STL_INTERNAL_ITERATOR_BASE_H #include <concept_checks.h> __STL_BEGIN_NAMESPACE // 五种迭代器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 {}; // input_iterator 定义template <class _Tp, class _Distance> struct input_iterator {  // 类别为 input_iterator_tag  typedef input_iterator_tag iterator_category;  typedef _Tp                value_type;  typedef _Distance          difference_type;  typedef _Tp*               pointer;  typedef _Tp&               reference;}; // output_iterator 定义struct output_iterator {  // 类别为 output_iterator_tag  typedef output_iterator_tag iterator_category;  typedef void                value_type;  typedef void                difference_type;  typedef void                pointer;  typedef void                reference;}; template <class _Tp, class _Distance> struct forward_iterator {  typedef forward_iterator_tag iterator_category;  // ...}; template <class _Tp, class _Distance> struct bidirectional_iterator {  typedef bidirectional_iterator_tag iterator_category;  // ...}; template <class _Tp, class _Distance> struct random_access_iterator {  typedef random_access_iterator_tag iterator_category;  // ...}; #ifdef __STL_USE_NAMESPACES// iterator 定义template <class _Category, class _Tp, class _Distance = ptrdiff_t,          class _Pointer = _Tp*, class _Reference = _Tp&>struct iterator {  typedef _Category  iterator_category;  typedef _Tp        value_type;  typedef _Distance  difference_type;  typedef _Pointer   pointer;  typedef _Reference reference;};#endif /* __STL_USE_NAMESPACES */ // 偏特化#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION // iterator_traits 模板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;}; // iterator_traits 针对指针的特化版本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;}; // iterator_traits 针对const指针的特化版本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;}; // 获取迭代器的类型 (返回一个该类型的对象)template <class _Iter>inline typename iterator_traits<_Iter>::iterator_category__iterator_category(const _Iter&){  typedef typename iterator_traits<_Iter>::iterator_category _Category;  return _Category();} // 获取迭代器的 __distance_typetemplate <class _Iter>inline typename iterator_traits<_Iter>::difference_type*__distance_type(const _Iter&){  return static_cast<typename iterator_traits<_Iter>::difference_type*>(0);} // 获取迭代器的 __value_typetemplate <class _Iter>inline typename iterator_traits<_Iter>::value_type*__value_type(const _Iter&){  return static_cast<typename iterator_traits<_Iter>::value_type*>(0);} // __iterator_category 的const参数版本template <class _Iter>inline typename iterator_traits<_Iter>::iterator_categoryiterator_category(const _Iter& __i) { return __iterator_category(__i); } // __distance_type 的const参数版本template <class _Iter>inline typename iterator_traits<_Iter>::difference_type*distance_type(const _Iter& __i) { return __distance_type(__i); } // __value_type 的const参数版本template <class _Iter>inline typename iterator_traits<_Iter>::value_type*value_type(const _Iter& __i) { return __value_type(__i); } #define __ITERATOR_CATEGORY(__i) __iterator_category(__i)#define __DISTANCE_TYPE(__i)     __distance_type(__i)#define __VALUE_TYPE(__i)        __value_type(__i) #else /* __STL_CLASS_PARTIAL_SPECIALIZATION */// 如果不支持偏特化,那么就需要定义iterator_category的函数重载的形式了// 这里略去了此部分源代码的解释,因为估计也只有{非主流}编译器才不支持偏特化吧 #endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */ // 体验traits技术的威力,针对不同的迭代器类型定义不同的distance实现版本// _InputIterator 版本template <class _InputIterator, class _Distance>inline void __distance(_InputIterator __first, _InputIterator __last,                       _Distance& __n, input_iterator_tag){  while (__first != __last) { ++__first; ++__n; }} // _RandomAccessIterator版本template <class _RandomAccessIterator, class _Distance>inline void __distance(_RandomAccessIterator __first,                        _RandomAccessIterator __last,                        _Distance& __n, random_access_iterator_tag){  __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);  __n += __last - __first;} // distance 接口// 注意 _RandomAccessIterator 也是 _InputIteratortemplate <class _InputIterator, class _Distance>inline void distance(_InputIterator __first,                      _InputIterator __last, _Distance& __n){  __STL_REQUIRES(_InputIterator, _InputIterator);  // 通过 iterator_category 取得迭代器类型  __distance(__first, __last, __n, iterator_category(__first));} #ifdef __STL_CLASS_PARTIAL_SPECIALIZATION// 对_Distance进行了特化template <class _InputIterator>inline typename iterator_traits<_InputIterator>::difference_type__distance(_InputIterator __first, _InputIterator __last, input_iterator_tag){  typename iterator_traits<_InputIterator>::difference_type __n = 0;  while (__first != __last) {    ++__first; ++__n;  }  return __n;} template <class _RandomAccessIterator>inline typename iterator_traits<_RandomAccessIterator>::difference_type__distance(_RandomAccessIterator __first, _RandomAccessIterator __last,           random_access_iterator_tag) {  __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);  return __last - __first;} template <class _InputIterator>inline typename iterator_traits<_InputIterator>::difference_typedistance(_InputIterator __first, _InputIterator __last) {  typedef typename iterator_traits<_InputIterator>::iterator_category     _Category;  __STL_REQUIRES(_InputIterator, _InputIterator);  return __distance(__first, __last, _Category());} #endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */ // 体验traits技术的威力,针对不同的迭代器类型定义不同的advance实现版本// _InputIterator 版本template <class _InputIter, class _Distance>inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {  while (__n--) ++__i;} #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)#pragma set woff 1183#endif // _BidirectionalIterator 之前前进与后退template <class _BidirectionalIterator, class _Distance>inline void __advance(_BidirectionalIterator& __i, _Distance __n,                       bidirectional_iterator_tag) {  __STL_REQUIRES(_BidirectionalIterator, _BidirectionalIterator);  if (__n >= 0)    while (__n--) ++__i;  else    while (__n++) --__i;} #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)#pragma reset woff 1183#endif // _RandomAccessIterator版本template <class _RandomAccessIterator, class _Distance>inline void __advance(_RandomAccessIterator& __i, _Distance __n,                       random_access_iterator_tag) {  __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);  __i += __n;} // advance 接口template <class _InputIterator, class _Distance>inline void advance(_InputIterator& __i, _Distance __n) {  __STL_REQUIRES(_InputIterator, _InputIterator);  __advance(__i, __n, iterator_category(__i));} __STL_END_NAMESPACE #endif /* __SGI_STL_INTERNAL_ITERATOR_BASE_H */

代码中有distance和advance两个函数,通过traits技术自动使用最佳的实现函数。

5. __type_traits
除了iterator_traits采用了traits技术外,还有一个叫做__type_traits的东西,也就是文章开头提到的:上一篇文章《STL笔记之空间配置器》就用到了__type_traits。

// 模拟true和false定义的两个空类型struct __true_type {}; struct __false_type {}; template <class _Tp>struct __type_traits {    typedef __true_type     this_dummy_member_must_be_first;   // 默认都是返回__false_type   // 无意义的构造函数   typedef __false_type    has_trivial_default_constructor;   // 无意义的复制构造函数   typedef __false_type    has_trivial_copy_constructor;   // 无意义的赋值操作符   typedef __false_type    has_trivial_assignment_operator;   // 无意义的析构函数   typedef __false_type    has_trivial_destructor;   // 是否是POD类型   typedef __false_type    is_POD_type;}; // #define __STL_TEMPLATE_NULL template<>// 这里定义的都是全特化版本__STL_TEMPLATE_NULL struct __type_traits<char> {   typedef __true_type    has_trivial_default_constructor;   typedef __true_type    has_trivial_copy_constructor;   typedef __true_type    has_trivial_assignment_operator;   typedef __true_type    has_trivial_destructor;   typedef __true_type    is_POD_type;};// ... // 用于判断一个函数是否是整数类型template <class _Tp> struct _Is_integer {  // 默认不是整数类型  typedef __false_type _Integral;}; // 全特化版本__STL_TEMPLATE_NULL struct _Is_integer<char> {  typedef __true_type _Integral;};

6. 迭代器设计模式
迭代器模式是GoF提出的23中设计模式之一,迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。就如刚接触map/set等关联容器的时候,我们能够通过迭代器访问所有容器元素,却不知道容器是用红黑树实现的一样。

迭代器模式的类图结构如下:
设计模式的迭代器模式类图


原文链接:http://www.programlife.net/stl-iterator.html,作者:代码疯子(Wins0n) 

0 0
原创粉丝点击