动态增长的数组vector,当它放入的元素满了的时候,会自动的扩充内存,但是,在计算机中内存不能够实现原地扩充,因为在申请了一块固定大小的内存之后,这块内存不管有没有用完,他后面的内存都有可能别的内容被占用。所以扩充的过程是在内存中别的地方找到一块足够大的内存,把原来的东西搬过去。

vector的内部示意图:

vector关键部分的实现代码: finish指向的是最后一个元素的后一个位置

可以先看一下vector定义的插入元素的方法,因为内存的扩容是发生在插入元素而内存不足的时候:

可以看到,在插入元素的时候,如果内存不足,会调用insert_aux的函数:

可以看到,insert_aux函数会开始的时候检查是否空间可用(很奇怪为什么到这里了还要检查空间是否够用,如果够用,则将元素继续插入到容器中,否则再次重新扩充内存,实际上,insert_aux函数不是是在这里被调用,它在其他地方也被调用,作为插入元素的函数,所以就会在刚开始的时候检查内存时候够用,这主要是针对别的地方调用它插入元素的时候使用的),可以看到,具体的内存扩充的代码在else语句里面,具体的实现如下所示:

所以在使用vector的时候,应该考虑到,在每次扩充内存的时候,会涉及到大量元素的拷贝动作,此时会调用拷贝构造函数,当拷贝完成后,释放掉原来的内存,需要同样调用析构函数,这是非常损耗性能的。

Vector的迭代器:

vector中迭代器的设计如下:

vector中迭代器的实现与前面讲的基本一样,也需要满足Iterator的一些基本的特征。

Array容器:

array本身就是C++种的数组,将它包装成容器,它就可以C++种容器的规律,比如可以提供迭代器,以便于让算法进行相应的操作,如果不将它数据进行这样的包装,数组就会被摈弃在STL的六大部件之外,失去了和这些部件之间的联系。

array的具体实现:

dequeue容器:
双向队列,内部的结构:

deque采用分段的方式(buffer),map指向的元素是一个指针,而这个指针指向的是buffer,所以map是一个只想指针的指针,存储map所指向的元素的容器是一个vector,。每一段buffer的元素满了的时候,deque会继续申请一块同样大小的内存,然后将内存的指针向前或者向后放入到map中,从而实现deque向前或者向后扩充。

deque的迭代器:

deque的迭代器有四个元素,cur, first,last, node, first指向内存段buffer的起始位置,last指向内存段buffer中最后一个元素的后一个位置(超尾),cur指向当前的元素,node指向当前buffer的指针, 也就是说指向vector中对应的指针。

可以看到dequeue的定义如下所示:

deque类中的定义的成员,可以看到map的类型,确实是指向指针的指针,还有迭代器start,  finish.,以及对应的begin(),end()方法。

下面可以看一下迭代器的具体实现,有助于理解上面的原理图:

可以看到迭代其中的四个元素,node的类型也可以知道,即node是指向指针的。

deque<T>::insert( )方法:

在deque中插入元素,deque会智能的通过插入的元素的位置而决定调用的方法:如果靠近头部,则会将插入元素到头部,如果靠近尾部,则会将元素插入尾部,否则,会采取另一种插入方法。

deque如何模拟连续空间:通过 deque iterator实现,可以看到deque内部定义的方法:

可以看到,size方法中,出现了两个迭代器相减,所以这个减法是一个重载的运算符,两个迭代器相减,返回荣光期内元素的个数,所以减号运算符的重载方法是:finish-start是map中元素的个数,而每个map中元素指向的buffer中有固定个数的元素(buffer size),所以可以根据这些值计算出容器中元素的个数。它的具体的实现如下所示:

其中,node是map种元素的指针(map种元素的内存是连续的)。所以(node - x.node - 1)就是map_size.

cur-first是当前迭代器种多出来的元素(没有放满一个buffer)

x.last-x.cur是另一个参与运算的迭代器中多出来的元素(没有放满一个buffer)

迭代器中++,--的实现:

// 前缀加
self& operator++()
{++cur;    // 切换到下一个元素if (cur == last)   // 当前的buffer已经放满了{set_node(node + 1);     // 跳到下一个node 节点  map中的下一个元素}return *this;
}// 后缀加
self& operator++(int dummy)
{self tmp = *this;++*this;       // 在后缀加中调用前缀加return tmp;
}

还有其他一些方法的实现,+=,-=等运算符的重载,

例如,在重载迭代器的+=运算符的时候,需要考虑到,每次加了之后,是否会超出当前的buffer,如果从超出,就需要切换到下一个node,具体的实现思路如下所示:

deque容器其他方法的实现也与此类似,都与要考虑到节点的切换问题:

容器,queue, stack

从上图可以看出queue,stack和deque的关系,在实现queue,stack的时候,不需要再重写一个queue和stack,我们只需让他们内含一个deque,然后再禁止deque中的某些方法即可,实现方法如下所示:

stack的实现:

-------------------------------------------------------end---------------------------------------------------------

C++ STL学习笔记(5) Vector容器, array容器,deque容器相关推荐

  1. SGI STL 学习笔记二 vector

    sequence containers Array Vector Heap Priority_queue List sList(not in standard) Deque Stack Queue S ...

  2. C++ STL学习笔记

    C++ STL学习笔记一 为何要学习STL: 数据结构与算法是编程的核心,STL中包含各种数据结构和优秀的算法,确实值得深入学习,本文中虽然着重使用,但希望有心的朋友能多看看相关数据结构的实现,对于C ...

  3. 【C++ STL学习笔记】C++ STL序列式容器(array,vector,deque,list)

    文章目录 C++ STL容器是什么? 迭代器是什么,C++ STL迭代器(iterator)用法详解 迭代器类别 迭代器的定义方式 C++序列式容器(STL序列式容器)是什么 容器中常见的函数成员 C ...

  4. C++STL学习笔记(4) 分配器(Allocator)

    在前面的博客<C++ STL学习笔记(3) 分配器Allocator,OOP, GP简单介绍>中,简单的介绍了分配器再STL的容器中所担当的角色,这一节对STL六大部件之一的分配器进行详细 ...

  5. C++ STL学习笔记(3) 分配器Allocator,OOP, GP简单介绍

    继续学习侯捷老师的课程! 在前面的博客<C++ STL学习笔记(2) 容器结构与分类>中介绍了STL中常用到的容器以及他们的使用方法,在我们使用容器的时候,背后需要一个东西支持对内存的使用 ...

  6. 菜鸟学习笔记:Java提升篇4(容器4——Collections工具类、其他容器)

    菜鸟学习笔记:Java容器4--Collections工具类.其他容器 Collections工具类 容器其他知识点 队列Queue Enumeration接口 Hashtable Propertie ...

  7. 菜鸟学习笔记:Java提升篇3(容器3——泛型、排序)

    菜鸟学习笔记:Java容器3--泛型.排序 泛型 泛型类 泛型接口 泛型方法 泛型继承 通配符"?" 泛型知识点补充 容器排序 Comparable接口与compareTo方法 C ...

  8. 菜鸟学习笔记:Java提升篇2(容器2——Map、Set、迭代器)

    菜鸟学习笔记:Java容器2--Map.Set.迭代器 Map容器 HashMap的使用 Hash表讲解 Map实现 Set容器 HashSet的使用 实现 Iterator迭代器 Map容器 Has ...

  9. 菜鸟学习笔记:Java提升篇1(容器1——List)

    菜鸟学习笔记:Java容器1--List容器 容器基本概念 List容器 ArrayList 初始化 add方法 remove方法 LinkList 链表 双向链表 初始化 add方法 remove方 ...

最新文章

  1. 干货丨入门机器学习,从搞懂这8大经典算法开始
  2. 制作嵌入式根文件系统(常见问题详解)
  3. 那些年的那些事CISC和RISC发展中的纠缠
  4. SQL Server 备份与恢复之八:还原数据库
  5. tomcat出现5个using_下肢深静脉血栓要警惕,出现这5个症状,马上看医生
  6. php网站接入微信支付,PHP接入微信H5支付的方法示例
  7. Ubuntu源码安装php-7.2.23
  8. Git/Github + TortoiseGit 使用教程
  9. VM10虚拟机安装图解
  10. linux 终端使用aplay播放wav
  11. 简单正则^(?![^a-zA-Z]+$)(?!\D+$)[0-9a-zA-Z]{6,35}$
  12. android转发短信到邮箱,利用短信通知的方式在Tasker中实现收到Android手机短信自动转发到邮箱...
  13. 使用python切割图片
  14. 百度糯米猴年初一夺冠  协同创新三大法器赢得漂亮
  15. 【转】固态硬盘恢复之30分钟大法操作技巧
  16. 联想电脑拯救者y7000触摸屏失灵的修复方法
  17. Ubuntu18如何下载微信和qq
  18. Flutter 功能最全的JsonToDart工具
  19. 香港理工大学智能计算实验室招收PhD/博士后/研究助理
  20. 正则表达式的字符串匹配

热门文章

  1. k8s核心技术-集群安全机制(RBAC实现鉴权)---K8S_Google工作笔记0040
  2. Netty工作笔记0046---TaskQueue自定义任务
  3. STM32工作笔记0029---认识电路原理图中的VCC,VDD,VEE,VSS
  4. C++容器删除数据时迭代器失效
  5. 根据sessionId获取Session对象
  6. 2017年(毕业生)暑期实习信息汇总
  7. boost学习之BOOST_FOREACH
  8. 随想录(文件系统的第一个用户程序shell)
  9. 计算机休眠状态播放音乐,win7系统休眠后不能播放音乐怎么解决
  10. python列表迭代器_python迭代器生成器-迭代器和list区别