[转载]《STL源码剖析》阅读笔记之 迭代器及traits编程技法

   本文从三方面总结迭代器

  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 = 0;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

转载于:https://www.cnblogs.com/HXloveLL/p/3698533.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/420967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python类

一&#xff0c;类 1&#xff0c;类是摸板&#xff0c;里面有组合数据&#xff0c;实现功能的方法。 2&#xff0c;类里面有可以改变自身的方法__init__函数 3&#xff0c;类和模块类似&#xff0c;运行时创建&#xff0c;创建后修改 4&#xff0c;类成员通常是public&#xff…

关于Coursera视频不能播放问题

1&#xff0c;打开C:\Windows\System32\drivers\etc目录&#xff1b; 2&#xff0c;修改host文件&#xff0c;在最后添加52.84.246.72 d3c33hcgiwev3.cloudfront.net&#xff0c;保存&#xff1b; 3&#xff0c;重启浏览器或者刷新Coursera视频网址&#xff0c;搞定。

Web Form要“jquery”ScriptResourceMapping。请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping。”的解决办法。...

1.先将aspnet.scriptmanager.jquery.dl 复制到bin (网站根目录下的bin文件夹找不到&#xff0c;看看下面的图片中点击[显示所有文档]) 文件夹下。 2.在网站根目录下scripts文件夹,向里边添加jquery-1.7.2.min.js和jquery-1.7.2.js(可根据自己需要使用不同的版本&#xff09;…

python继承多重继承

一&#xff0c;基本语法 class MyClass(BaseClass):def __init__(self):print(...)class MyDefineClass(object):def __init__(self):print(继承自object类)MyDefineClass.__init__(None) # 属性访问 me MyDefineClass() # 实例对象 继承自object类 继承自object类 二&#x…

第14章 任务和特权级保护

学习这一章感觉异常的困难&#xff0c;所以学习从14-17章&#xff0c;每一章学扎实了&#xff0c;弄懂了每个问题再进行下一章&#xff0c;后一章都是在前一章的基础上增加一些数据结构和机制。另外读的时候可以各个击破&#xff0c;每次只搞明白一个小问题。读这一章可能需要两…

python 生成器推导式

# 生成器 generator 用yield来返回数据 def reverse(data):for i in range(len(data) - 1, -1, -1): # range(start, end, step) 不包括endyield data[i]def test_generator():for char in reverse(abc):print(char)# test_generator()c b a生成器表达式&#xff1a;与列表推导…

Windows XP系统安装SQL Server 2005(开发版)图解

转自Windows XP系统安装SQL Server 2005(开发版)图解 安装前提:由于有些从网上的下载的项目需要导入SQL Server 2005的数据文件&#xff0c;因此&#xff0c;今天便安装了这个数据库&#xff0c;我的系统中已经安装了SQL Server2000所以是在它之上安装SQL Server2005的。 一、数…

《软件工程(C编码实践篇)》课后感

Fibonacci&#xff08;与最后申请证书的姓名务必一致&#xff09; 原创作品 《软件工程&#xff08;C编码实践篇&#xff09;》MOOC课程http://mooc.study.163.com/course/USTC-1000002006 1&#xff08;20分&#xff09;软件工程&#xff08;C编码实践篇&#xff09;学习总…

用turtle画各种各样的数学图形

ps&#xff0c;用turtle导入小海龟来画图。画图代码都要导入海龟库哦&#xff0c;见下面第一行。 import turtle as t直线 # 画直线 def draw_line():pen t.Pen()pen.fd(200) # 直线默认水平方向 draw_line() 画正方形 def draw_square():pen t.Pen()for i in range(4): …

从网络字节流中提出整数

最近在做一个项目&#xff0c;就是设计一套通信协议&#xff0c;利用nginx来实现解析。协议内容是包括整数和字符串&#xff0c;现在客户端收到服务器端发送的网络字节流时&#xff0c;需要从中提取出整数&#xff0c;再根据整数决定发送数据量的大小。如下所示&#xff1a; p …

实验3 系统调用

系统调用 实验目的 建立对系统调用接口的深入认识掌握系统调用的基本过程能完成系统调用的全面控制为后续实验做准备 实验内容 此次实验的基本内容是&#xff1a;在Linux 0.11上添加两个系统调用&#xff0c;并编写两个简单的应用程序测试它们。 iam() 第一个系统调用是iam()&a…

python标准库(一)

操作系统接口os 切换目录 >>> import os>>> os.getcwd() # 得到当前工作目录C:\\Users>>> os.chdir(F:\\) # 切换工作目录到F盘>>> os.system(mkdir tody) # 在f盘创建一个叫tody的文件夹0import os 与 from os import * &#xff0c;要…

[Java] webservice soap,wsdl 例子

java 调用webservice的各种方法总结 现在webservice加xml技术已经逐渐成熟&#xff0c;但要真正要用起来还需时日!! 由于毕业设计缘故&#xff0c;我看了很多关于webservice方面的知识&#xff0c;今天和大家一起来研究研究webservice的各种使用方法。 一、利用jdk web服务api…

C语言ASM汇编内嵌语法zz

朋友们&#xff0c;我是从http://www.cnblogs.com/latifrons/archive/2009/09/17/1568198.html这里转载过来的&#xff0c;很不错就收藏了&#xff0c;如果转载&#xff0c;请注明初始链接。 .3 GCC Inline ASM GCC 支持在C/C代码中嵌入汇编代码&#xff0c;这些汇编代码被称作…

python标准库(二)

格式化输出 reprlib 库用来格式化 >>> import reprlib >>> reprlib.repr(set(aabbccddeeeff)) "{a, b, c, d, e, f}" >>>对集合能排序 >>> reprlib.repr(set(fdajfejaa)) "{a, d, e, f, j}" >>>pprint库用…

templates(0.1)

每一位 C 程序员都有自己的一套编程风格。这就引来了各种问题&#xff1a;哪儿应该 插入空白符号、怎么摆放分隔符&#xff08;大括号、小括号&#xff09;…等等。我们尽量保持全书风格一致&#xff0c; 当然有时候我们也对特殊问题作出让步。例如在教本&#xff08;初阶&…

实验4 进程运行轨迹的跟踪与统计

进程运行轨迹的跟踪与统计 难度系数&#xff1a;★★★☆☆ 实验目的 掌握Linux下的多进程编程技术&#xff1b;通过对进程运行轨迹的跟踪来形象化进程的概念&#xff1b;在进程运行轨迹跟踪的基础上进行相应的数据统计&#xff0c;从而能对进程调度算法进行实际的量化评价&…

虚拟环境创建,pip管理包

windows10虚拟环境的创建&#xff0c;pip管理包1.虚拟环境的创建1.1 为什么要创建虚拟环境1.2 创建虚拟环境1.3 激活虚拟环境1.3.1 激活方式1.3.2 检查是否创建成功2.用pip管理包2.1 pip的基本使用2.2 pip创建安装的文件requirements.txt2.3 安装包对应的版本2.4 用pip - r ins…

Linux C编程一些优秀的博客链接

1&#xff0c;C进程内存分布 https://www.cnblogs.com/fengyv/p/3789252.html 2&#xff0c;fork入门讲解 http://blog.csdn.net/jason314/article/details/5640969

vi文字处理器

http://blog.csdn.net/wangloveall/article/details/22649331 摘要&#xff1a;vi是类UNIX命令行接口的标准文字处理软件&#xff0c;也是进行shell脚本程序编写与服务器设置的非常重要的工具。本文介绍vi文字处理器&#xff0c;包括vi简介、vi怎么使用、vi的加强版vim。 关键词…