迭代器是一种行为类似指针的对象。迭代器最重要的工作是operator*、operator ->、operator ++。

每一种STL容器都提供专属迭代器。

根据迭代器所支持的操作,可以把迭代器分为五类:

(1). 输入迭代器(input iterator)是只读迭代器,在每个被遍历到的位置上只能被读取一次。

(2). 输出迭代器(output iterator)是只写迭代器,在每个被遍历到的位置上只能被写入一次。

输入和输出迭代器的模型分别是建立在针对输入和输出流(例如文件)的读写操作的基础上的。所以不难理解,输入和输出迭代器最常见的表现形式是istream_iterator和ostream_iterator。

(3). 前向迭代器(forward iterator)兼具输入和输出迭代器的能力,但是它可以对同一个位置重复进行读和写。前向迭代器不支持operator--,所以它只能向前移动。所有的标准STL容器都支持比前向迭代器功能更强大的迭代器。

(4). 双向迭代器(bidirectional iterator)很像前向迭代器,只是它们向后移动和向前移动同样容易。标准关联容器都提供了双向迭代器。list也是如此。

(5). 随机访问迭代器(random access iterator)有双向迭代器的所有更能,而且,它还提供了”迭代器算术”,即在一步内向前或向后跳跃的能力。vector、string和deque都提供了随机访问迭代器。指向数组内部的指针对于数组来说也是随机访问迭代器。

 //输出迭代器例子ostream_iterator<int> outite(cout, " ");int ia[] = { 0,1,2,3,4,5 };deque<int> id(ia, ia + 6);copy(id.begin(), id.end(), outite);

2.1 迭代器相应类型概念、应用场景 & 偏特化概念
在实际的算法中,在运用迭代器时,会用到迭代器所指对象中的相应类型(associate type)。

那么算法实现中该如何满足 声明一个以“迭代器所指对象(中)的类型”为类型的成员/参数,或返回值是“迭代器所指对象(中)的类型”的类型 的需求呢?

可分为以下三种情况:

① 迭代器所指对象是c++内置类型;
② 迭代器所指对象是自定义类型(class type)情形;
③ 迭代器所指对象是原生指针(naive pointer)情形;
对应的运用以下三种方法解决:

① function template的参数推导(augument deducation)机制 ;
② 声明内嵌类型 ;
③ 利用泛化中偏特化(partial secification)(下面有解释) ;
envolve to :萃取机 iterator_traits 机制
注意:这三种方法是逐步整合为最终的实现的方案就是 iterator_traits萃取机 机制,它包含了函数模板的参数推导,声明内嵌类型和偏特化所有内容,也同时解决了以上的三个场景的实现需求。

偏特化(template partial specification):如果class template拥有一个以上的template参数,可以对其中某个(或数个,但非全部)template进行特化工作,其中偏特化有两种形式:

1. 对template参数的部分个参数进行特化;
2. 对template参数的范围进行限定;
两种形式见下图所示:

偏特化其实就可以理解为“针对任何template参数进一步地进行条件限制所设计出的特化版本”。那么对应的,全特化(full specification) 就是指对模板参数不做任何限制。

如上,利用对(常量)指针类型的偏特化,解决了内嵌类型无法解决的迭代器所指对象是原生指针类型的问题。

最终设计出了迭代器萃取机这一中间层,其作用是萃取出迭代器的相关特性(也即是相应类型的取用),以屏蔽迭代器实现对算法实现的影响。如左下图所示

在图中列出了原生指针(pointer),还单独列出了常量指针(pointer-to-const)(对于const关键字的解析见:const限定符)。对于常量指针,泛化版本的iterator::traits<const int*> value_type会返回一个const int,也即返回值是一个无法进行赋值的临时变量,所以针对常量指针的value_type类型应当特化为非常量类型,如下

template <class T>
struct iterator_traits<const T*> { //偏特化版本——当迭代器是一个pointer-to-const时typedef T value_type;          //萃取出的类型应当是T而非常量const T//...
};//附上指针的偏特化萃取实现
struct iterator_traits<T*> {typedef T value_type;//...
};

所以只要迭代器的实现者在实现过程中,将内嵌类型和原生类型遵循约定,以内嵌类型(nested typedef)的方式定义(typedef)出STL迭代器萃取机所规定的相关类型,就可以与STL标准实现兼容,实现算法实现和容器实现的剥离。

如右上图(iterator_traits对常用内嵌类型的typedef)所示,迭代器中最常用到的迭代器类型有五种,整理出如下表格:

迭代器相关类型    说明
value_type    所谓value type,指的是迭代器所指对象的类型。任何一个与STL有完美搭配的class,都应该定义value type内嵌类型
difference_type    difference type表示两个迭代器之间的距离,因此也可用来表示一个容器的最大容量(头尾距离),以alogrithm中的count()为例:

对于原生指针,c++内建了ptrdiff_t(位于<cstddef>头文件内)作为原生指针的difference type(在iterator_traits<(const) T*>中使用);
当需要迭代器I的difference type,可以写typename iterator_traits<I>::difference_type,如上图中例;
reference    首先根据迭代器能否更改所指的对象,可以分为constant iterators和mutable iterators两种;
对应两种迭代器:
如果iterator是const的,那么若是其value_type是T,那么返回值应当是const T&;
如果iterator是mutable的,那么若是其value_type是T,那么返回值应当为T&;
pointer    指向迭代器所指之物/对象的类型的指针的类型;
iterator_category    对于迭代器种类,若是良好的利用好category的继承关系,可以极大地提高算法的效率,种类的具体解释和继承关系如下面图中所示。以advance()函数为例可以探讨category对算法的影响,详细内容见《STL源码剖析》p93,运用到了类的多态性,向上类型转换(派生类转基类,is-a继承关系)。

符合规范,任何迭代器都应提供五个内嵌相应类别,以利于traits萃取。STL为此提供了一个iterators class,也即std::iterator如下,如果每个新设计的迭代器继承自它,就可保证STL所需之规范:

distance 函数:

用来计算两个迭代器之间的距离。

STL源码剖析之迭代器相关推荐

  1. 【STL源码剖析】迭代器

    [STL源码剖析]迭代器 第3章 迭代器(iterators)与traits编程技法(<STL源码剖析> ) 3.1 迭代器设计思维--STL关键所在 3.2 迭代器(iterator)是 ...

  2. 【STL源码剖析】list模拟实现 | 适配器实现反向迭代器【超详细的底层算法解释】

    今天博主继续带来STL源码剖析专栏的第三篇博客了! 今天带来list的模拟实现! 话不多说,直接进入我们今天的内容! 前言 那么这里博主先安利一下一些干货满满的专栏啦! 手撕数据结构https://b ...

  3. SGL STL源码剖析——迭代器

    SGL STL源码剖析--迭代器 迭代器 迭代器的型别 Traits的作用 迭代器相应的五种型别 __type_traits 迭代器 在我们使用STL容器的时候,迭代器是非常常见的,STL将容器和算法 ...

  4. STL源码剖析学习七:stack和queue

    STL源码剖析学习七:stack和queue stack是一种先进后出的数据结构,只有一个出口. 允许新增.删除.获取最顶端的元素,没有任何办法可以存取其他元素,不允许有遍历行为. 缺省情况下用deq ...

  5. STL源码剖析面试问题

    当vector的内存用完了,它是如何动态扩展内存的?它是怎么释放内存的?用clear可以释放掉内存吗?是不是线程安全的? vector内存用完了,会以当前size大小重新申请2* size的内存,然后 ...

  6. STL源码剖析 数值算法 copy 算法

    copy复制操作,其操作通过使用assignment operator .针对使用trivial assignment operator的元素型别可以直接使用内存直接复制行为(使用C函数 memove ...

  7. STL源码剖析 算法开篇

    STL源码剖析 算法章节 算法总览_CHYabc123456hh的博客-CSDN博客 质变算法 质变算法 - 会改变操作对象的数值,比如互换.替换.填写.删除.排列组合.分隔.随机重排.排序等 #in ...

  8. STL源码剖析 map

    所有元素会根据元素的键值自动被排序 元素的类型是pair,同时拥有键值和实值:map不允许两个元素出现相同的键值 pair 代码 template <class T1,class T2> ...

  9. STL源码剖析 slist单向链表概述

    概述 SGI STL的list是一个双向链表,单向链表是slist,其不在标准规格之内 单向和双向链表的区别在于,单向链表的迭代器是单向的 Forward Iterator,双向链表的迭代器属于双向的 ...

  10. STL 源码剖析 heap堆

    heap不属于STL容器的组件,属于幕后角色,是priority_queue的助手 priority_queue 允许用户以任何次序将任何元素推入容器内,但是取出的时候需要从优先级最高(也就是数值最高 ...

最新文章

  1. HarmonyOS 设置图标在Text 旁边
  2. 系统架构性能问题诊断及优化思路,纯干货!
  3. Python中的Numpy模块(1,numpy创建)
  4. SQLite AND/OR 运算符(http://www.w3cschool.cc/sqlite/sqlite-and-or-clauses.html)
  5. 河南招教考试计算机专业知识,河南教师招聘考试《计算机网络技术基础》知识点归纳七...
  6. SQLite | Insert、Delete、Updata 与 Drop 语句
  7. 进程句柄和进程ID的区别和关系
  8. 漫步数理统计二十一——变换:随机向量
  9. android字符串显示textview,Android编程:TextView不显示完整字符串
  10. 干货:不同场景容器内获取客户端源IP的方法
  11. oracle10g debian,Debian Sarge 上安装 Oracle 10g
  12. 繁体转简体 java_【Java】简体中文、繁体中文转换
  13. vi中跳到首行或尾行
  14. Airbnb、小猪短租等这类短租类产品发展前景如何?
  15. JAVA8 Map新方法:compute,computeIfAbsent,putIfAbsent与put的区别
  16. Linux编译之(1)C语言基础
  17. 解决webview 刷新问题,返回刷新webview,webview 刷新不好使
  18. Aspose.Words模板创建Word【一】
  19. 部分HTTPS网站无法访问的可能原因
  20. Ubuntu Github基本使用方法

热门文章

  1. 对输入的两个整数按大小顺序输出
  2. html中给select下拉框赋值
  3. LSTM 文本分类模型的实现
  4. 输入一正整数,将各数字反转后输出
  5. wireshark抓包方法及数据分析
  6. java水电费收费系统_基于jsp的电费管理系统-JavaEE实现电费管理系统 - java项目源码...
  7. 计算机工程主编陶小雪,城市环境所在MOFs基催化剂的制备和VOCs催化氧化方面取得进展...
  8. 移动pc一套代码_【腾讯】如何避免 CDN 为 PC 端缓存移动端页面
  9. c语言编程怎么记,新手如何学习c语言
  10. java中级项目案例_60个Java练手项目案例,看了让你茅塞顿开~