本文从三方面总结迭代器

  1.   迭代器的思想
  2.   迭代器相应型别及traits思想
  3.   __type_traits思想

一 迭代器思想

迭代器的主要思想源于迭代器模式,其定义如下:提供一种方法,使之能够依序巡防某个聚合物(容

器)所含的元素,而又无需暴露该聚合物的内部表达式。可见她的主要作用便是能够降低耦合,提高代码的

模块性。

STL的的中心思想在于:将数据容器和算法分开,彼此独立设计,最后再以一贴胶着剂将它们撮合

在一,这贴胶着剂便是迭代器。迭代器的行为类似智能指针(例如标准库的auto_ptr和boost库的shared

_ptr),换句话说它重载了* 和 –> 运算符,由于设计一个适用于所有容器的迭代器是非常困难的,每个

迭代器都必须很了解容器,所以STL的每一种容器都提供了相应的专属迭代器。

STL在广义上有5种迭代器类型(不限于这5种,还可以是原生指针等,具体的容器定义自己的迭代器但

是类型是这几种之一或者是原生指针等)

  •    input iterator : 这种迭代器所指对象不允许外界改变,即是只读的
  •    output iterator : 唯写
  •    forward iterator : 允许写入型算法
  •    bidirectional iterator : 可双向移动的迭代器
  •    random access iterator :  涵盖所有指针运算能力,可随机访问任何位

它们在STL中的定义如下:

template <class T, class Distance> struct input_iterator {
typedef input_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
struct output_iterator {
typedef output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
};
template <class T, class Distance> struct forward_iterator {
typedef forward_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T, class Distance> struct bidirectional_iterator {
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T, class Distance> struct random_access_iterator {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};

二 迭代器相应型别及traits思想

书中把traits技法称为STL源代码的门钥,可见其十分重要。先介绍迭代器相应型别,从字面上意义来

说便是和迭代器相关的类型信息,实际上有5种常用的迭代器类型:

  •     value type : 迭代器所指对象的型别
  •     difference type : 迭代器之间的距离型别
  •     reference type : 迭代器引用型别
  •     pointer type : 迭代器指针型别
  •     iterator_category : 迭代器本身的型别

STL内部需要知道当前的迭代器的这些型别信息,其所使用的方法主要是模板的参数推导、模板内嵌型

别以及模板偏特化。这里介绍下模板偏特化的概念。

模板的偏特化是指任何template参数更进一步的条件限制所设计出来的一个特化版本,例如

template<typename T>

class C{…}     //这个版本允许T为任何类型

template<typename T>

class C<T*>{…} //这个特化版本仅适用于“T为原生指针的”的情况,它比上面的更特殊

有了模板偏特化,就可以让traits萃取出原生指针(譬如vector的迭代器就是原生指针型别的)以及指

向常量的原生指针型别而不仅仅是类类型的,而负责萃取的便是 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;
};

如果是类类型的性别,用上面这个就可以获得其5个相应型别,当然这些型别必须都在相应iterator类

里面定义好(见第一节的5种迭代器的定义),那么如果不是上面5种而是原生指针等其他型别呢?这时候

就用到了模板偏特化:

//原生指针用这个
template <class T>
struct iterator_traits<T*> {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
//指向常量的原生指针用这个
template <class T>
struct iterator_traits<const T*> {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
};

通过这个traits我们就可以获得任何一种iterator的相应型别,通过以下表达式即可:

iterator_traits<…>::…

说到这里有一个很重要是设计思想不得不提,就是通过函数重载在编译时决策正确的函数调用。这个问

题源于5种迭代器的类型,它们的巡防能力是不同的,例如random acess iterator是巡防能力最强的,可以

在O(1)时间巡防指定位置,而这个用其他的迭代器可能需要O(n)。所以为了提高效率,我们应该用和迭代器

类型最匹配的算法函数去调用,能用random access iterator的就不要用其他的。那么怎么做呢?

  •     首先通过traits获得iterator_category,这样我们能够知道当前迭代器的类型。实际上iterator_category就是用来提供这种服务的。
  •     在函数调用时生成相应迭代器类型的临时对象作为实参传递,编译器就会调用相应的重载函数。

为了重载函数识别,我们有对应的5种迭代器标识类:

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

继承是为了可以使用传递调用,当不存在某种迭代器类型匹配时编译器会依据继承层次向上查找进行传递。
以distance为例:
//这里category()就是为了产生临时对象
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());
}
//input iterator 版,注意函数形参最后的类型
template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
__distance(InputIterator first, InputIterator last, input_iterator_tag) {
iterator_traits<InputIterator>::difference_type n = ;
while (first != last) {
++first; ++n;
}
return n;
}
//random access iterator 版
template <class RandomAccessIterator>
inline iterator_traits<RandomAccessIterator>::difference_type
__distance(RandomAccessIterator first, RandomAccessIterator last,
random_access_iterator_tag) {
return last - first;
}

三 __type_traits思想

有了前面的基础,我们理解到STL是非常重视效率的,而SGI STL又在其基础上实现了一个

__type_traits,根据前面的经验我们知道它是一个萃取剂,只不过它萃取的型别是:

  •     是否具备non-trivial default ctor?
  •     是否具备non-trivial copy ctor?
  •     是否具备non-trivial assignment operator?
  •     是否具备non-trivial dtor?

这里的non-trivial意指非默认的相应函数,我们知道编译器会为每个类构造以上四种默认的函数,如

果没有定义自己的,就会用编译器默认函数,如果使用默认的函数,本来就是按位拷贝我们可以使用memcpy

等函数来加快速度,提高效率。

为了使用函数重载决议,我们使用类类型来定义两种类型,__true_type和__false_type

struct __true_type {
};
struct __false_type {
};
template <class type>
struct __type_traits {
typedef __true_type this_dummy_member_must_be_first;
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;
typedef __false_type is_POD_type;
};
这个是泛化版,STL对几乎每种内置类型都定义了相应的特化版本来制定它们的类型,整体实现不难。
 
后记:
通过迭代器的设计,我们能够看到很多非常有价值的思想,也对模板的强大有了更加深刻的认识,这些也是
继续阅读STL源码的基础。

转载地址:http://www.cnblogs.com/HappyAngel/archive/2011/04/19/2021413.html

[转载]《STL源码剖析》阅读笔记之 迭代器及traits编程技法的更多相关文章

  1. STL源码剖析 阅读笔记

    结构图:

  2. STL源码剖析读书笔记之vector

    STL源码剖析读书笔记之vector 1.vector概述 vector是一种序列式容器,我的理解是vector就像数组.但是数组有一个很大的问题就是当我们分配 一个一定大小的数组的时候,起初也许我们 ...

  3. c++ stl源码剖析学习笔记(一)uninitialized_copy()函数

    template <class InputIterator, class ForwardIterator>inline ForwardIterator uninitialized_copy ...

  4. 重温《STL源码剖析》笔记 第三章

    源码之前,了无秘密. --侯杰 第三章:迭代器概念与traits编程技法 迭代器是一种smart pointer auto_Ptr 是一个用来包装原生指针(native pointer)的对象,声明狼 ...

  5. STL源码剖析读书笔记--第四章--序列式容器

    1.什么是序列式容器?什么是关联式容器? 书上给出的解释是,序列式容器中的元素是可序的(可理解为可以按序索引,不管这个索引是像数组一样的随机索引,还是像链表一样的顺序索引),但是元素值在索引顺序的方向 ...

  6. 重温《STL源码剖析》笔记 第六、七、八章 next_permutation (字典序)

    源码之前,了无秘密  ——侯杰 第六章算法 next_permutation 比如:01342 -> 01423 -> 01432 方法:从尾端开始往前寻找两个相邻的元素,令第一个元素为* ...

  7. 重温《STL源码剖析》笔记 第五章

    源码之前,了无秘密  ——侯杰 序列式容器 关联式容器 array(build in) RB-tree vector set heap   map priority-queue multiset li ...

  8. 重温《STL源码剖析》笔记 第一章

    源码之前,了无秘密. --侯杰 经典的书,确实每看一遍都能重新收获一遍: 第一章:STL简介 STL的设计思维:对象的耦合性极低,复用性极高,符合开发封闭原则的程序库. STL的价值:1.带给我们一套 ...

  9. 重温《STL源码剖析》笔记 第四章

    源码之前,了无秘密  ——侯杰 序列式容器 关联式容器 array(build in) RB-tree vector set heap   map priority-queue multiset li ...

随机推荐

  1. ECSHOP在线手册之模板结构说明 (适用版本v2.7.3)

    名称 类型 备注(作用或意义) 文件(目录)名可否更改 images 目录 存放模板图片目录 不可更改 library 目录 存放模板库文件目录 不可更改 screenshot.png 图片 用于“后 ...

  2. Files to be needed by importing the android application with eclipse

    1. AndroidManifest.xml 2. project.properties # This file is automatically generated by Android Tools ...

  3. iOS开发——高级技术&密码锁功能的实现

    密码锁功能的实现 一个ios手势密码功能实现 ipad/iphone 都可以用 没有使用图片,里面可以通过view自己添加 keychain做的数据持久化,利用苹果官方KeychainItemWrap ...

  4. typedef和typename关键字

    .类型说明typedef 类型说明的格式为: typedef 类型 定义名; 类型说明只定义了一个数据类型的新名字而不是定义一种新的数据类型.定义名表示这个类型的新名字. 例如: 用下面语句定义整型数 ...

  5. C 二叉树 1

    二叉链表: #define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include & ...

  6. C 二叉树

    二叉树表示法 P127页 /* typedef struct BiTNode { int data; struct BiTNode *lchild, *rchild; }BiTNode, *BiTre ...

  7. (转)如何在JavaScript与ActiveX之间传递数据3

    本文研究如何在JS等脚本语言与ActiveX控件之间通信,如何传递各种类型的参数,以及COM的IDispatch接口.使用类似的方法,可以推广到其他所有脚本型语言,如LUA,AutoCad等.本文将研 ...

  8. JQuery图片滑动插件

    效果预览: (暂无) html代码: <div id="focus"> <ul> <li> <a href="#"&g ...

  9. 迷你template

    JavaScript Micro-Templatinghttp://ejohn.org/blog/javascript-micro-templating/   //Simple JavaScript ...

  10. LLBLGen代码生成工具

    LLBLGen代码生成工具 下载地址:http://www.llblgen.com/ 最新版本4.2 概述 LLBLGen是一个数据访问的解决方案; 你使用LLBLGen创建实体/域模型,定义了映射和 ...