• STL源码分析-iterator(迭代器)


    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的迭代器类型为双向迭代器。

    ![](https://img2018.cnblogs.com/blog/1285081/201809/1285081-20180925233604703-939646533.png)

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

    2018年9月25日23:44:02

  • 相关阅读:
    spring源码学习之【准备】cglib动态代理例子
    spring源码学习之【准备】jdk动态代理例子
    eclipse使用jetty插件出现内存溢出解决方案
    SpringMVC Controller 返回值的可选类型
    spring之bean的作用域scope的值的详解
    SVN与Git的区别
    java thread yield 的设计目的是什么?
    JAVA Set 交集,差集,并集
    Executor, ExecutorService 和 Executors 间的区别与联系
    java.util.concurrent.Executors类的常用方法介绍
  • 原文地址:https://www.cnblogs.com/blog-yejy/p/9704114.html
Copyright © 2020-2023  润新知