1. GOF 迭代器设计模式

前面一篇文章有写到stl_list的实现,也实现了一下相应的iterator,但是后面觉得,实现具体容器之前有必要介绍一下iterator(迭代器)
。那么迭代器是什么呢?

GOF的设计模式是这样定义的: 提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。

大概意思是,例如一个聚合对象(list),我们该如何来访问它的元素,而又不暴露内部结构;而且还要针对不同的需要,可能以不同的方式遍历这个list;那么即使,我们知道大概会有哪些遍历操作,那我们也不会希望list接口中充斥着各种不同遍历操作。一句话,就是如果把遍历和操作元素的各种方法都放到list中来实现,那么将会导致list类中结构变得混乱而且不稳定。

正好迭代器就是用来提供给外部访问聚合对象元素的一个结构。 那GOF设计模式,采用的实现方式是OOP(面向对象),类图关系如下:

具体的聚合对象有自己的继承关系,具体的iterator也有自己的继承关系,也就是通过继承多态来实现用户侧代码无需修改,就可以兼容不同的聚合对象。在GOF设计模式书中专门有一点提到:使用多态迭代器是有代价的。他们要求用一个Factory Method动态分配迭代器对象。因此仅当必须多态时才使用它们。

2. STL 迭代器

在C++ STL中,也是继承了GOF提出的迭代器基本需求,并且迭代器(iterator)扮演着重要角色,来将将容器和算法分开,彼此独立设计,最后再以胶着剂(iterator)将它们撮合在一起。

那么C++ STL实现iterator和GOF介绍的迭代器实现方法什么区别呢? 那首先我们需要了解C++中的两个编程范式的概念,GP(泛型编程)和OOP(面向对象编程)。

在C++语言里面,我们可以以下方式来简单区分一下GP和OOP:

GP: 泛型编程,也被称为"静态多态",多种数据类型在同一种算法或者结构上皆可操作,其效率与针对某特定数据类型而设计的算法或者结构相同, 具体数据类型在编译期确定,编译器承担更多,代码执行效率高。在STL中利用GP将methods和datas实现了分而治之。

OOP: 将methods和datas关联到一起 (通俗点就是方法和成员变量放到一个类中实现),通过继承的方式,利用虚函数表(virtual)实现运行时类型判定,也叫"动态多态", 由于运行过程中需根据类型去检索虚函数表,因此效率相对较低。

刚好,C++ STL库的整个实现采用的就是GP(Generic Programming),而不是OOP(Object Oriented Programming)。而GOF设计模式采用的
就是继承关系实现的,因此,相对来讲,C++ STL的实现效率会相对较高,而且也更有利于维护。

3. STL iterator分类和总结

迭代器类型基本关系:

STL 迭代器基本介绍:

1、输入迭代器:只读,一次传递

可为输入迭代器预定义实现只有istream_iterator和istreambuf_iterator,用于从一个输入流istream中读取。一个输入迭代器仅能对它所选择的每个元素进行一次解析,它们只能向前移动。一个专门的构造函数定义了超越末尾的值。总是,输入迭代器可以对读操作的结果进行解析(对每个值仅解析一次),然后向前移动。

2、输出迭代器:只写,一次传递

这是对输入迭代器的补充,不过是写操作而不是读操作。为输出迭代器的预定义实现只有ostream_iterator和ostreambuf_iterator,用于向一个输出流ostream写数据,还有一个一般较少使用的raw_storage_iterator。他们只能对每个写出的值进行一次解析,并且只能向前移动。对于输出迭代器来说,没有使用超越末尾的值来结束的概念。总之,输出迭代器可以对写操作的值进行解析(对每一个值仅解析一次),然后向前移动。

3、前向迭代器:多次读/写

前向迭代器包含了输入和输出迭代器两者的功能,加上还可以多次解析一个迭代器指定的位置,因此可以对一个值进行多次读/写。顾名思义,前向迭代器只能向前移动。没有为前向迭代器预定义迭代器。

4、双向迭代器:operator--

双向迭代器具有前向迭代器的全部功能。另外它还可以利用自减操作符operator--向后一次移动一个位置。由list容器中返回的迭代器都是双向的。

5、随机访问迭代器:类似于一个指针

随机访问迭代器具有双向迭代器的所有功能,再加上一个指针所有的功能(一个指针就是一个随机访问迭代器),除了没有一种“空(null)”迭代器和空指针对应。基本上可以这样说,一个随机访问迭代器就像一个指针那样可以进行任何操作,包括使用操作符operator[]进行索引,加某个数值到一个指针就可以向前或者向后移动若干个位置,或者使用比较运算符在迭代器之间进行比较。

可以参考一下之前list实现的iterator代码,iterator内部维护一个list节点指针,然后对++和--进行操作符重载时,其实是指针的前后移动,因此stl_list的迭代器类型为双向迭代器。

迭代器作为STL的一个重要组成部分,今天算是做了一个简单的总结,在后续分析STL其他内容的过程中也会经常遇到!

2018年9月25日23:44:02

STL源码分析-iterator(迭代器)的更多相关文章

  1. STL源码分析之迭代器

    前言 迭代器是将算法和容器两个独立的泛型进行调和的一个接口. 使我们不需要关系中间的转化是怎么样的就都能直接使用迭代器进行数据访问. 而迭代器最重要的就是对operator *和operator-&g ...

  2. STL源码分析-iterator

    http://note.youdao.com/noteshare?id=4efcb6441063dae956c226f91c161897

  3. STL源码分析《4》----Traits技术

    在 STL 源码中,到处可见 Traits 的身影,其实 Traits 不是一种语法,更确切地说是一种技术. STL库中,有一个函数叫做 advance, 用来将某个迭代器(具有指针行为的一种 cla ...

  4. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

  5. STL源码分析《3》----辅助空间不足时,如何进行归并排序

    两个连在一起的序列 [first, middle) 和 [middle, last) 都已经排序, 归并排序最核心的算法就是 将 [first, middle) 和 [middle, last) 在  ...

  6. STL 源码分析《1》---- list 归并排序的 迭代版本, 神奇的 STL list sort

    最近在看 侯捷的 STL源码分析,发现了以下的这个list 排序算法,乍眼看去,实在难以看出它是归并排序. 平常大家写归并排序,通常写的是 递归版本..为了效率的考虑,STL库 给出了如下的 归并排序 ...

  7. STL 源码分析《2》----nth_element() 使用与源码分析

    Select 问题: 在一个无序的数组中 找到第 n 大的元素. 思路 1: 排序,O(NlgN) 思路 2: 利用快排的 RandomizedPartition(), 平均复杂度是 O(N) 思路 ...

  8. STL源码分析与实现-stl_list容器

    1. stl_list 介绍 今天我们来总结一下stl_List, 通过之前介绍单链表的文章,其实对链表的基本操作已经十分熟悉了,那对于stl_list,无非就是链表结构不一样,至于其中的增删改查的细 ...

  9. STL 源码分析六大组件-allocator

    1. allocator 基本介绍 分配器(allocator))是C ++标准库的一个组件, 主要用来处理所有给定容器(vector,list,map等)内存的分配和释放.C ++标准库提供了默认使 ...

随机推荐

  1. E20180419-hm

    rectangle n. [数] 长方形,矩形; ratio n. 比例; 比,比率; 系数;  vt. 求出比值,除,使…成比例; 将(相片)按比例放大[缩小]; aspect  n. 方面; 面貌 ...

  2. E20180413-hm

    skew adj. 斜的,歪的; [数学] 不对称的; [统计学] 歪斜,扭曲;   vt. 歪曲; 曲解; 使歪斜;   vi. 偏离,歪斜; 斜视; traversal  n. 横越,横断物,(横 ...

  3. float以后设置的小细节

    先看看下面这段css代码,是不是很完美?没错? #pageBodyMain .articleList a: after { content: ""; clear: both; di ...

  4. yii1 compoment实现自己的db类

    突然发现yii1并没有实现mysql的读写分离默认配置,而用yii1的配置实现读写分离又很麻烦,所以我写了一个db的辅助类 首先我们需要配置一下一下辅助db的compoment类,yii的compom ...

  5. 学习Mahout(一)

    Mahout 官方下载地址:http://apache.fayea.com/apache-mirror/mahout/ 环境ubuntu 12.04, hadoop1.2.1 ,mahout 0.9 ...

  6. curl:出现SSL错误提示

    在上一篇博文中,升级ruby版本中,提示如下错误: 1) Error fetching https://mirrors.aliyun.com/rubygems/: [root@web ~]# gem ...

  7. Linux下备份MySQL数据库的Shell脚本

    数据库每天都想备份,手动备份太麻烦而又容易忘记,所以写了一个自动备份MySQL数据库的脚本,加入定时计划中,每天自运运行. 创建Shell脚本代码如下,命名为mysql_dump.sh #!/bin/ ...

  8. Python函数和面向对象题目

  9. UvaLive3942(Trie + dp)

    查了半天数组越界的RE,才发现自己把ch数组放结构体里是过大的……放全局就A了. 类似区间的dp比较显然,只是用trie树做了优化,使得可以在trie树里一边走一边往上加dp值,不必枚举以前的每个位置 ...

  10. 1-8继承extends

    什么是继承? 继承是面向对象三大特征之一.java中的继承描述的是两个类之间的关系,被继承的类称为父类,继承的类称为子类,使用extends关键字来表示.在java语言里面只支持单继承,即一个类只能有 ...