deque源码1(deque概述、deque中的控制器)

deque源码2(deque迭代器、deque的数据结构)

deque源码3(deque的构造与内存、ctor、push_back、push_front)

deque源码4(deque元素操作:pop_back、pop_front、clear、erase、insert)

deque的构造与内存

deque自行定义了两个专属的空间配置器:

  1. protected:
  2. typedef simple_alloc<value_type,Alloc> data_allocator; //专属空间配置器,每次配置一个元素大小
  3. typedef simple_alloc<pointer,Alloc> map_allocator; //专属空间自配器,每次配置一个指针大小
  4.  
  5. deque(int n,const value_type& value):
  6. start(),finish(),map(0_,map_size(){
  7. fill_initialize(n,value);
  8. }
  1. fill_initialize()负责产生并安排好deque的结构,并将元素的初值设定妥当:
  1. template <class T,class Alloc,size_t BufSize>
  2. void deque<T.Alloc,BufSize>::fill_initialize(size_type n,const value_type& value){
  3. create_map_and_nodes(n); //把deque的结构都产生并安排好
  4. map_pointer cur;
  5. __STL_TRY{
  6. //为每个节点的缓冲区设定初值
  7. for(cur=start.node;cur<finish.node;++cur)
  8. uninitialized_fill(*cur,*cur+buffer_size(),value):
  9. uninitialized_fill(finish.first,finish.cur,value);
  10. }
  11. catch(...){
  12. ...
  13. }
  14. }

其中create_map_and_nodes()负责产生并安排好deque的结构:

  1. template <class T,class Alloc,size_t BufSize>
  2. void deque<T,Alloc,BufSize>::create_map_and_nodes(size_type num_elements){
  3. //需要的节点数=(元素个数/每个缓冲区可容纳的元素个数)+1
  4. //如果刚好除整数,会多配置一个节点
  5. size_type num_nodes=num_elements/buffer_size()+;
  6. //一个map要管理几个节点,最少8个,最多是"所需节点数加2"
  7. //前后各预备一个,扩充时可用
  8. map_size=max(inital_map_size(),num_nodes+);
  9. map=map_allocator::allocate(map_size); //配置出一个"具有map_size个节点"的map
  10. //以下令nstart和nfinish指向map所拥有之全部节点的最中央区段
  11. //保持在最中央,可使头尾两端的扩充能量一样大,每个节点可对应一个缓冲区
  12. map_pointer nstart=map+(map_size-num_nodes)/;
  13. map_pointer nfinish=nstart+num_nodes-;
  14.  
  15. map_pointer cur;
  16. __STL_TRY{
  17. //为map内的每个现用节点配置缓冲区,所有缓冲区加起来就是deque的可用空间(最后一个缓冲区可能留有一些富裕)
  18. for(cur=nstart;cur<=nfinish;++cur)
  19. *cur=allocate_node();
  20. }
  21. catch(...){
  22. //若成功全部执行,不成功一个都不执行
  23. ...
  24. //为deque内的两个迭代器start和end设定正确内容
  25. start.set_node(nstart);
  26. finish.set_node(nfinish);
  27. start.cur=start.first;
  28. finish.cur=finish.first+num_element%buffer_size();//整除时,会多配一个节点,cur指向该节点缓冲区的起始处
  29. }
  30. }

举一个例子,代码如下,deque状态如下图:

  1. deque<int> mydeque(,);
  2. for(int i=;i<mydeque.size();i++)
  3. mydeque[i]=i;
  4. for(int i=;i<;i++)
  5. mydeque.push_back(i);

push_back()函数内容如下:

  1. public:
  2. void push_back(const value& t){
  3. if(finish.cur!=finish.last-){
  4. //最后缓冲区上有至少一个备用空间
  5. construct(finish.cur,t); //直接在备用空间上构造元素
  6. ++finish.cur; //调整最后缓冲区的使用状态
  7. }
  8. else //最后缓冲区已无元素备用空间或者只有一个元素备用空间
  9. push_back_aux(t);
  10. }

接着上面的例子,再在mydeque后面添加一个元素3,由于尾端只存在一个元素的备用空间,所以必须调用push_back_aux,先配置一整块的缓冲区,再添加新的元素,deque状态如下:

push_back_aux()函数内容如下:

  1. //只有最后一个缓冲区只剩一个备用元素空间时才会被调用
  2. template <class T,class Alloc,size_t BufSize>
  3. void deque<T,Alloc,BufSize>::push_back_aux(const value_type& t){
  4. value_type t_copy=t;
  5. reserve_map_at_back(); //若符合某种条件则必须重换一个map
  6. *(finish.node+)=allocate_node(); //配置一个新的节点(缓冲区)
  7. __STL_TRY{
  8. construct(finish.cur,t_copy); //针对标的元素设置
  9. finish.set_node(finish.node+); //改变finish,令其指向新节点
  10. finish.cur=finish.first; //设定finish的状态
  11. }
  12. __STL_UNWIND(deallocate_node(*(finish.node+)));
  13. }

接着上面的例子,在mydeque的前端插入99,deque状态如下:

push_front()函数操作如下:

  1. public:
  2. void push_front(const value& t){
  3. if(satrt.cur!=start.first){
  4. //第一缓冲区尚有备用空间
  5. construct(start.cur-,t); //直接在备用空间上构造元素
  6. --start.cur; //调整第一缓冲区的使用状态
  7. }
  8. else //第一缓冲区已无备用空间
  9. push_front_aux(t);
  10. }

由上图可知,这里必须调用push_front_aux(),push_front_aux()函数操作如下:

  1. //只有第一个缓冲区只剩一个备用元素空间时才会被调用
  2. template <class T,class Alloc,size_t BufSize>
  3. void deque<T,Alloc,BufSize>::push_back_aux(const value_type& t){
  4. value_type t_copy=t;
  5. reserve_map_at_front(); //若符合某种条件则必须重换一个map
  6. *(start.node-)=allocate_node(); //配置一个新的节点(缓冲区)
  7. __STL_TRY{
  8. start.set_node(start.node-); //改变start,令其指向新节点
  9. start.cur=start.last-; //设定start的状态
  10. construct(start.cur,t_copy); //针对标的元素设值
  11. }
  12. catch(...){
  13. //若成功全部执行,若失败全部执行
  14. start.set_node(start.node+);
  15. start.cur=satrt.first;
  16. deallocate_node(*(start.node-));
  17. throw;
  18. }
  19. }

reserve_map_at_back、reserve_map_at_front

reserve_map_at_back()、reserve_map_at_front()这两个函数会在什么时候调用?答案是它们会在map需要重新整治的时候,也就是map的节点备用空间不足的时候。

reserve_map_at_front()函数操作如下:

  1. void reserve_map_at_front(size_type nodes_to_add=){
  2. if(nodes_to_add>start.node-map) //如果map前端的节点备用空间不足,则必须重新换一个map
  3. reallocate_map(nodes_to_add,true); //配置更大的,拷贝原来的,释放原来的
  4. }

reserve_map_at_back()函数操作如下:

  1. void reserve_map_at_back(size_type nodes_to_add=){
  2. if(nodes_to_add+>map_size-(finish.node-map)) //如果map尾端的节点备用空间不足,则必须重新换一个map
  3. reallocate_map(nodes_to_add,false);
  4. }

reallocate_map()函数操作如下:

  1. template <class T,class Alloc,size_t BufSize>
  2. void deque<T,Alloc,BufSize>::reallocate_map(size_type nodes_to_add,bool add_at_front){
  3. size_type old_num_nodes=finish.node-start.node+;
  4. size_type new_num_nodes=old_num_nodes+nodes_to_add;
  5. map_pointer new_nstart;
  6. if(map_size>*new_num_nodes){
  7. new_nstart=map+(map_size-new_num_nodes)/+(add_at_front?nodes_to_add:);
  8. if(new_nstart<start.node)
  9. copy(start.node,finish.node+,new_nstart);
  10. else
  11. copy_backward(start.node,finish.node+,new_nstart+old_num_nodes);
  12. }
  13. else{
  14. size_type new_map_size=map_size+max(map_size,node_to_add)+;
  15. //配置一块空间,准备给新map使用
  16. map_pointer new_map=map_allocator::allocte(new_map_size);
  17. new_nstart=new_map+(new_map_size-new_num_nodes)/+(add_at_front?nodes_to_add:);
  18. //把原map内容拷贝过来
  19. copy(start.node,finish.node+,new_nastart);
  20. //释放原map
  21. map_allocator::deallocate(map,map_size);
  22. //设定新map的起始地址与大小
  23. map=new_map;
  24. map_size=new_map_size;
  25. }
  26. //重新设定迭代器start和finish
  27. start.set_node(new_nstart);
  28. finish.set_node(new_nstart+old_num_nodes-);
  29. }

deque源码3(deque的构造与内存、ctor、push_back、push_front)的更多相关文章

  1. deque源码4(deque元素操作:pop_back、pop_front、clear、erase、insert)

    deque源码1(deque概述.deque中的控制器) deque源码2(deque迭代器.deque的数据结构) deque源码3(deque的构造与内存.ctor.push_back.push_ ...

  2. deque源码2(deque迭代器、deque的数据结构)

    deque源码1(deque概述.deque中的控制器) deque源码2(deque迭代器.deque的数据结构) deque源码3(deque的构造与内存.ctor.push_back.push_ ...

  3. deque源码1(deque概述、deque中的控制器)

    deque源码1(deque概述.deque中的控制器) deque源码2(deque迭代器.deque的数据结构) deque源码3(deque的构造与内存.ctor.push_back.push_ ...

  4. spark 源码分析之十六 -- Spark内存存储剖析

    上篇spark 源码分析之十五 -- Spark内存管理剖析 讲解了Spark的内存管理机制,主要是MemoryManager的内容.跟Spark的内存管理机制最密切相关的就是内存存储,本篇文章主要介 ...

  5. LRU工程实现源码(一):Redis 内存淘汰策略

    目录 内存淘汰是什么?什么时候内存淘汰 内存淘汰策略 Redis中的LRU淘汰算法 源码剖析 第一步:什么时候开始淘汰key 配置读取 检查时机 getMaxmemoryState 第二步:淘汰哪些k ...

  6. jQuery.buildFragment源码分析以及在构造jQuery对象的作用

    这个方法在jQuery源码中比较靠后的位置出现,主要用于两处.1是构造jQuery对象的时候使用 2.是为DOM操作提供底层支持,这也就是为什么先学习它的原因.之前的随笔已经分析过jQuery的构造函 ...

  7. 手把手带你阅读Mybatis源码(一)构造篇

    前言 今天会给大家分享我们常用的持久层框架——MyBatis的工作原理和源码解析,后续会围绕Mybatis框架做一些比较深入的讲解,之后这部分内容会归置到公众号菜单栏:连载中…-框架分析中,欢迎探讨! ...

  8. Python 源码剖析(六)【内存管理机制】

    六.内存管理机制 1.内存管理架构 2.小块空间的内存池 3.循环引用的垃圾收集 4.python中的垃圾收集 1.内存管理架构 Python内存管理机制有两套实现,由编译符号PYMALLOC_DEB ...

  9. spark 源码分析之十五 -- Spark内存管理剖析

    本篇文章主要剖析Spark的内存管理体系. 在上篇文章 spark 源码分析之十四 -- broadcast 是如何实现的?中对存储相关的内容没有做过多的剖析,下面计划先剖析Spark的内存机制,进而 ...

随机推荐

  1. Redis学习笔记:与SpringBoot结合使用

    首先需要在pom文件中导入相应的Redis依赖(版本可以会变化,下面坐标也可能会变化) <dependency> <groupId>org.springframework.bo ...

  2. 一次性获取PPT图片方法

    XXX.ppt 改成 XXX.zip 或者 XXX.rar 解压,查看文件夹即可

  3. 实验十四 第九组 张燕~杨蓉庆~杨玲 Swing图形界面组件

    实验十四  Swing图形界面组件 8-11-29 理论知识 Swing和MVC设计模式 (1)设计模式(Design pattern)是设计者一种流行的 思考设计问题的方法,是一套被反复使用,多数人 ...

  4. Js高级程序设计~读书笔记

    1.函数-函数声明和函数表达式 解析器在向执行环境加载数据时,函数声明和函数表达式的对待不同. 解析器会率先执行函数声明,将会在任何使用到它的地方前加载, 而对于函数表达式,只会在执行到的时候去加载: ...

  5. SAS 创建新变量

    SAS  创建新变量 在对SAS数据集进行处理时,经常需要根据原有变量或变量值生成新变量.根据要实现功能的不同,SAS提供了多种方法,例如通过数据集选项RENAME=(RENAME语句).赋值语句.求 ...

  6. css隐藏多余的文字并出现省略号

    <meta charset="utf-8" /> <style> .txt{ width:200px; border:1px solid #ddd; ove ...

  7. etcd 增减节点

    一.查看集群节点 etcdctl --endpoint=https://10.2.0.6:2379 --ca-file=/etc/etcd/ca.pem --cert-file=/etc/etcd/c ...

  8. Win7 VS2017编译magnum及例子

    magnum是一个开源的图形中间件 Lightweight and modular C++11/C++14 graphics middleware for games and data visuali ...

  9. IDEA的Find菜单使用

    想要显示Find菜单在底部,如图: 选中一个类,如Cloneable,然后按键Ctrl+Alt+B(相当于eclipse中的ctrl+T) 显示如图,选择最右上角的固定标签 就会把它固定在控制台菜单中 ...

  10. unic

    在线考试 答题剩余时间0小时51分18秒 考生须知 1.本次考试结束后,剩余补考次数:2次 2.考试时间为60分钟,超时系统自动交卷 3.本次考试满分100分(5*20道),60分通过考试 1. (单 ...