《STL源码剖析》学习笔记之一 迭代器

来源:互联网 发布:儿童编程培训班多少钱 编辑:程序博客网 时间:2024/05/21 18:31

1.        迭代器

迭代器是算法(业务逻辑)和容器之间的黏合剂。

迭代器关键是重载operator*operator->,前者可以作为左值,后者返回指针;前者的语意是取得迭代器指向的对象,后者的语意是取得迭代器指向对象的地址。

单向链表,重载operator++()和operator++int),前者可以作为左值,后者不能作为左值。

1.1.       function template的参数推导(argument deducation

function template的参数推导(argument deducation)机制?

似乎hp版的STL并未使用参数推导机制?

       function templatede参数推导机制无法解决推导函数的返回值型别。

1.2.       Traits编程技法

迭代器所指对象的类型,称为该迭代器的value type

采用内嵌类型来解决问题(前提是迭代器是class type)。

但不是所有迭代器都是class type,例如原生指针(如int * p)。

1.3.       采用偏特化和增加中间层来解决原生指针问题

增加的中间层如下:

template<class Iter>  // 模型形参Iter为一个迭代器

struct iterator_traits

{

       typedef typename Iter::value_type value_type;        // 当迭代器为非原生指针采用

                                                                                // 其内嵌类型value_type

};

似乎hp版并未使用偏特化?

文中提到的指针偏特化似乎VC6.0编译器不支持?

 

1.4.       value type

value type迭代器所指对象类型,iterator内嵌类型之一。任何一个迭代器必须定义自己的value type内嵌类型。

 

1.5.       difference type

difference type表示两个迭代器之间距离变量的类型,iterator内嵌类型之一。

例如vector的定义:

template<class _Ty, class _A = allocator<_Ty> >

class vector {

public:

       ……

       typedef _A::difference_type difference_type;   // difference type采用其分配器

// difference type

       ……

};

template<class _Ty>

class allocator {

public:

       ……

       typedef _PDFT difference_type; // _PDFT就是int

       ……

};

vector自己的迭代器中使用:

class const_iterator : public _Ranit<_Bool, difference_type> {

       public:

              ……

              // 计算两个迭代器距离

              difference_type operator-(const const_iterator _X) const

                     {return (_VBITS * (_Ptr - _X._Ptr)

                            + (difference_type)_Off

                            - (difference_type)_X._Off); }

              ……

};

1.6.       reference type

根据迭代器所指对象是否可以改变,可将迭代器分为两种:constant iteratorsmutable iterators

reference type指迭代器所指对象的引用类型,即传回一个左值表示迭代器所指之对象,iterator内嵌类型之一。同样也分为constantnon-constant

例如:

template<class _Ty, class _A = allocator<_Ty> >

class vector {

public:

       ……

       typedef _A::reference reference;

       typedef _A::const_reference const_reference;

       ……

       const_reference at(size_type _P) const

              {if (size() <= _P)

                     _Xran();

              return (*(begin() + _P)); }

       reference at(size_type _P)

              {if (size() <= _P)

                     _Xran();

              return (*(begin() + _P)); }

       const_reference operator[](size_type _P) const

              {return (*(begin() + _P)); }

       reference operator[](size_type _P)

              {return (*(begin() + _P)); }

       ……

       };

1.7.       pointer type

pointer type之迭代器所指对象的指针类型,即传回一个左值表示迭代器所指之对象的地址。

例如:

template<class _Ty, class _A = allocator<_Ty> >

class list {

protected:

       ……

       typedef _A::pointer _Tptr;

       typedef _A::const_pointer _Ctptr;

       ……

       class const_iterator : public _Bidit<_Ty, difference_type> {

       public:

              ……

              _Ctptr operator->() const

                     {return (&**this); }

              ……

              };

       ……

       class iterator : public const_iterator {

       public:

              ……

              _Tptr operator->() const

                     {return (&**this); }

              ……

              };

};

1.8.       iterator_category

iterator_category指迭代器类型变量之类型(有点拗口,呵呵),iterator内嵌类型之一。

迭代器分为5类:

1)        input iterator:迭代器所指对象只读;

2)        output iterator:迭代器所指对象只写;

3)        forward iterator:前向迭代器,所指对象可读写;

4)        bidirectional iterator:双向迭代器,所指对象可读写;

5)        random access iterator:随机访问迭代器,所指对象可读写。

其从属关系如下图:

input iterator

output iterator

forward iterator

bidirectional iterator

random access iterator

迭代器分类与从属关系

其中箭头代表的并非继承而是概念(concept)和强化(refinement)关系。

效率是研究STL过程中的一个重要课题,也是建立一个函数库的重要考虑的方面。假使有个算法可接受forward iterator,你用random access iterator喂给它也行,但不代表最佳!记住够用就好!!

 

正是基于效率才有以下advance()改进:

advance函数有两个形参:pn,函数将迭代器累进n次。

 

基于效率考虑,advance调用三个实现细节:advance_IIadvance_BIadvance_RAI,分别用来实现input iteratorbidirectional iteratorrandom access iterator三种迭代器累进n。三个实现细节如下:

template<class InputIterator, class Distance >

void advance_II(InputIterator & i, Distance n)

{

       while(n--) // 假设n大于0

              i++;

}

template<class BidirectionalIterator, class Distance >

void advance_II(BidirectionalIterator & i, Distance n)

{

       if(n >= 0)

{

              while(n--)                  

i++;

}

else

{

              while(n++)                

i--;

}

}

template<class RandomAccessIterator, class Distance >

void advance_II(RandomAccessIterator & i, Distance n)

{

       i += n;

}

然后,advance函数根据需要调用相应的实现,如下:

template< class InputIterator, class Distance >

void advance(InputIterator & i, Distance n)

{

       if(is_random_access_iterator(i))

       {

              advance_RAI(i, n);

       }

       else if(is_bidirectional_iterator(i))

       {

              advance_BI(i, n);

       }

       else

       {

              advance_II(i, n);

       }

}

这里存在一个效率问题,这种分支结构是执行期决定使用哪个版本,能否在编译期决定采用哪个版本呢?

采用重载的方式解决这个问题!

定义三个实现重载:

template<class InputIterator, class Distance>

inline void __advance(InputIterator & i, Distance n, input_iterator_tag)

{

       while (n--)

       {

              ++i;

       }

}

 

template<class BidirectionalIterator, class Distance>

inline void __advance(InputIterator & 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)

{

       i += n;

}

 

input_iterator_tagbidirectional_iterator_tagrandom_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  {};

结构的继承关系描述了5种迭代器类型的从属关系。为了使效率最高,结构不包含任何成员,即是一个空结构;同时,__advance形参中只定义其类型,并未指定其名称,标明其只是用来激活重载机制。

然后advance函数的调用采用traits机制和重载机制完成针对不同需求调用不同的实现的要求:

template<class InputIterator, class Distance>

inline void advance(InputIterator & i, Distance n)

{

       __advance(i, n, iterator_traits<InputIterator>::iterator_category());

}

这里之所以采用InputIterator,是因为STL的一个命名规则:以算法所能接受之最低阶迭代器类型,来为其迭代器类型参数命名。

1.9.       消除“单纯传递调用的函数”

这里之所以采用InputIterator,是因为STL的一个命名规则:以算法所能接受之最低阶迭代器类型,来为其迭代器类型参数命名。

什么叫“单纯传递调用的函数”呢?例如__advanceforward iterator版:

template<class ForwardIterator, class Distance>

inline void __advance(ForwardIterator & i, Distance n, forward_iterator_tag)

{

       while (n--)

       {

              ++i;

       }

}

__advanceinput iterator版相比,只是模板的第一个形参和函数最后一个形参不同,其实现部分完全相同,该函数仅仅是为了重载时传递调用的函数。

而调用重载函数进行参数匹配时的继承机制可以消除这一点,即当参数不匹配时,根据实参类型继承树向上搜索,其算法(单继承,多重继承类似)描述如下:

1)        以实参类型为被匹配类型;

2)        判断被匹配类型是否与某个重载函数形参相匹配,匹配进入4

3)        以被匹配类型的基类作为新的被匹配类型,返回2;若被匹配类型无基类,进入5

4)        调用该函数;

5)        编译器报错。

由于forward_iterator_tag派生至input_iterator_tag,因此可以省略单纯传递调用的函数__advanceforward iterator版,这也正是采用继承机制实现5种迭代器类型的重要原因!

1.10.   std::iterator的保证

为了避免STL库开发者开发的容器中迭代器不满足要求,STL提供一个迭代器基类如下:

template<class Category,

        class T,

               class Distance = ptrdiff_t,

               class Pointer = T*, /* 实际上hp版的STL并不包含该项 */

               class Reference = T&/* 实际上hp版的STL并不包含该项 */>

       struct iterator {

       typedef Category iterator_category;

       typedef T value_type;

       typedef Distance difference_type;

       typedef Pointer pointer; /* 实际上hp版的STL并不包含该项 */

       typedef Reference reference; /* 实际上hp版的STL并不包含该项 */

};

hpSTL看,hpSTL认为Pointer typeReference type并不是iterator必备特性之一?

原创粉丝点击