《STL源码剖析》迭代器(iterators)

C++的class templates和function templates可以实现容器和算法的泛型化。难点和关键是设计这两者的胶着剂角色——迭代器——提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴漏该容器的内部数据结构和内部表述方式。

迭代器是一种Samart pointer。

每一种STL容器都提供有专属的迭代器!原因:为了让实现细节封装起来而不让使用者看到,所以把迭代器的开发工作交给了具体容器的设计者。

泛型指针,原生指针和智能指针:
1. 泛型指针 泛型指针有多种含义。 (1) 指void*指针,可以指向任意数据类型,因此具有“泛型”含义。 (2) 指具有指针特性的泛型数据结构,包含泛型的迭代器、智能指针等。 广义的迭代器是一种不透明指针,能够实现遍历访问操作。通常所说的迭代器是指狭义的迭代器,即基于C++的STL中基于泛型的iterator_traits实现的类的实例。 总体来说,泛型指针和迭代器是两个不同的概念,其中的交集则是通常提到的迭代器类。
2. 原生指针就是普通指针,与它相对的是使用起来行为上象指针,但却不是指针。 说“原生”是指“最简朴最基本的那一种”。因为现在很多东西都抽象化理论化了,所以“以前的那种最简朴最基本的指针”只是一个抽象概念(比如iterator)的表现形式之一。 原生指针即   (类型名*p)样子的指针,类型名可以是基础类型,如int,double等,也可以是一个自己定义的Class类,相反的如果一个类重载了‘*’和‘->’的运算符,可以像指针一样用‘*’和‘->’操作,就不是原生的,如iterator等。auto_ptr(在头文件memory),这是一个用来包装原生指针的对象。
3. 智能指针是C++里面的概念:由于 C++ 语言没有自动内存回收机制,程序员每次得自己处理内存相关问题,但用智能指针便可以有效缓解这类问题。 引入智能指针可以防止出现悬垂指针的情况 一般是把指针封装到一个称之为智能指针类中,这个类中另外还封装了一个使用计数器,对指针的复制等操作将导致该计数器的值加1,对指针的delete操作则会减1,值为0时,指针为NULL。

Traits编程技法(特性萃取机)——解决迭代器常用的五种相应型别:

0、首先,我们来分析一下为什么要引入所谓的Traits。(不断加入限制条件(特例),繁衍traits的由来)
一个容器可以装各种不同类型的数据,结合value type,也就是说指迭代器所指对象的型别是各种各样的。为了解决获取“迭代器所指对象的型别”,比如“以“迭代器所指对象的型别”为型别 来 声明一个变量”,我们首先会想到function template的参数推导机制。p85——作函数参数。

我们知道,“template参数推导机制”推而导之的知识参数类型,无法推导函数的返回值型别。所以,万一,value type必须用于函数的传回值,“template参数推导机制”就行不通了。为了解决这个问题,声明内嵌型别似乎是一个好主意。p86——做函数返回值.

但是,并不是所有迭代器都是class type!原生指针就不是!如果不是原生指针,就无法定义内嵌型别。、?????STL以及整个泛型思维绝对必须接受原生指针作为一种迭代器。。。?????????。所以,为了让一般化概念针对特定情况做特殊化处理,我们使用——template partial specialization——在泛化设计中提供一个特化版本,也就是将泛化版本中某些template参数赋予明确的指定,提供另外一份template定义式,而其本身仍旧是templatized。
template <typename T>
class C {......}      //这个泛化版本允许接受T为任何型别

template <typename T>
class C {......}      //这个特化版本仅适用于“T为原生指针”的情况。,解决了内嵌型别未能解决的问题。

Traits,其实就是内嵌型别方法的一种升级——Traits特性萃取机,约定:自行 以内嵌型别定义的方式 定义出相应型别。

template <class T>
struct iterator_traits
{
typedef typename I::iterator_category iterator_category;
typedef typename I::value_type value_type;
typedef typename I::difference_type difference_type;
typedef typename I::pointer pointer;
typedef typename I::reference reference;
}
iterator_traits必须针对传入之型别为 pointer 以及 pointer-to-const 者,设计特化版本。各相应型别的具体设计详见下面。

Traits的意义是:如果 I 定义有自己的value type,那么通过traits 的作用,萃取出来的就是I::value type。不论面对的是迭代器MyIterator,或者是原生指针int * ,或者是const Int *,我们都可以通过Traits取出正确的value type。

Traits编程技法——利用“内嵌型别”的编程技巧与编译器的template参数推导功能,增强C++未能提供的关于型别认证方面的能力,弥补C++不是强型别语言的遗憾。

1、迭代器相应型别之一:value type——指迭代器所指对象的型别
在类中定义自己的value type内嵌型别。

2、迭代器相应型别之二:difference type——用来表示两个迭代器之间的距离

template < class I ,class T>
typename iterator_traits<T>::difference_type const(I first, I last, const T& value)
{
	typename iterator_traits<I>::difference_type n = 0;
	for (; first != last; ++first)
	{
		if (*first == value)
			++n;
	}
	return n;
}

template <class I>
struct iterator_traits{
	typedef typename I::difference_type difference_type;
};
template <class I>
struct iterator_traits<T*>{        //针对原生指针而设计的“偏特化”版本
	typedef ptrdiff_t difference_type;
};
template <class I>
struct iterator_traits<const T*>{  //针对原生的pointer-to-const 而设计的“偏特化”版本
	typedef ptrdiff_t difference_type;
};
有了上面的设计,很显然我们就可以在需要任何迭代器I的difference type的时候,统一这么写:
           typename iterator_traits<T>::difference_type

3、迭代器相应型别之三:reference type;迭代器相应型别之四:pointer  type

Item& operator*()  const { return *ptr; }
Item* operator->() const { return  ptr; }
Item&是reference type,Item*是pointer type。“传回一个左值,令它代表p所指之物”是可以的,“传回一个地址,令它代表所指之物的地址”也是可以的。

4、迭代器相应型别之五:iterator_category——迭代器类别
iterator_category表示迭代器的分类,共有五类。input_iterator、output_iterator、forward_iterator、bidirectional_iterator、random_access_iterator,分别是只读、只写、前向移动读写、双向移动读写、随机读写。

此处,为了消除“单纯传递调用的函数”,STL运用了C++的重载技术,比如advance函数。先来看一下五种迭代器类型的从属关系:

《STL源码剖析》迭代器(iterators)_第1张图片
//迭代器各类间的关系  
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 {}; 
如果没有上面的继承机制,我们就需要像下面一样,去传递一个调用函数:
template <class InputIterator, class Distance>
inline void _advance(InputIterator& i, Distance n, input_iterator_tag)  //第一个函数——单向,逐一前进
{
	while (n--) ++i;
}

template <class ForwardIterator, class Distance>
inline void _advance(ForwardIterator& i, Distance n, forward_iterator_tag)  
{
	_advance(i, n, input_iterator_tag);   //单纯的进行传递调用
}
我们再来看使用继承机制后的调用情况:
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(BidirectionalIterator& 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;  
}  
template <class InputIterator, class Distance>   //控制接口——继承的使用
inline void advance(InputIterator& i, Distance n)
{
<span style="white-space:pre">	</span>_advance(i, n, iterator_traits(InputIterator)::iterator_category()); //产生一个暂时对象(就像int()会产生一个int暂时对象),具体调用哪一个待决定
}
《STL源码剖析》源代码下载: http://pan.baidu.com/s/1c0x2kP6

你可能感兴趣的:(STL,traits)