deque源码3(deque的构造与内存、ctor、push_back、push_front)
deque源码3(deque的构造与内存、ctor、push_back、push_front)
deque源码4(deque元素操作:pop_back、pop_front、clear、erase、insert)
deque的构造与内存
deque自行定义了两个专属的空间配置器:
protected:
typedef simple_alloc<value_type,Alloc> data_allocator; //专属空间配置器,每次配置一个元素大小
typedef simple_alloc<pointer,Alloc> map_allocator; //专属空间自配器,每次配置一个指针大小 deque(int n,const value_type& value):
start(),finish(),map(0_,map_size(){
fill_initialize(n,value);
}fill_initialize()负责产生并安排好deque的结构,并将元素的初值设定妥当:template <class T,class Alloc,size_t BufSize>
void deque<T.Alloc,BufSize>::fill_initialize(size_type n,const value_type& value){
create_map_and_nodes(n); //把deque的结构都产生并安排好
map_pointer cur;
__STL_TRY{
//为每个节点的缓冲区设定初值
for(cur=start.node;cur<finish.node;++cur)
uninitialized_fill(*cur,*cur+buffer_size(),value):
uninitialized_fill(finish.first,finish.cur,value);
}
catch(...){
...
}
}其中create_map_and_nodes()负责产生并安排好deque的结构:
template <class T,class Alloc,size_t BufSize>
void deque<T,Alloc,BufSize>::create_map_and_nodes(size_type num_elements){
//需要的节点数=(元素个数/每个缓冲区可容纳的元素个数)+1
//如果刚好除整数,会多配置一个节点
size_type num_nodes=num_elements/buffer_size()+;
//一个map要管理几个节点,最少8个,最多是"所需节点数加2"
//前后各预备一个,扩充时可用
map_size=max(inital_map_size(),num_nodes+);
map=map_allocator::allocate(map_size); //配置出一个"具有map_size个节点"的map
//以下令nstart和nfinish指向map所拥有之全部节点的最中央区段
//保持在最中央,可使头尾两端的扩充能量一样大,每个节点可对应一个缓冲区
map_pointer nstart=map+(map_size-num_nodes)/;
map_pointer nfinish=nstart+num_nodes-; map_pointer cur;
__STL_TRY{
//为map内的每个现用节点配置缓冲区,所有缓冲区加起来就是deque的可用空间(最后一个缓冲区可能留有一些富裕)
for(cur=nstart;cur<=nfinish;++cur)
*cur=allocate_node();
}
catch(...){
//若成功全部执行,不成功一个都不执行
...
//为deque内的两个迭代器start和end设定正确内容
start.set_node(nstart);
finish.set_node(nfinish);
start.cur=start.first;
finish.cur=finish.first+num_element%buffer_size();//整除时,会多配一个节点,cur指向该节点缓冲区的起始处
}
}
举一个例子,代码如下,deque状态如下图:
deque<int> mydeque(,);
for(int i=;i<mydeque.size();i++)
mydeque[i]=i;
for(int i=;i<;i++)
mydeque.push_back(i);
push_back()函数内容如下:
public:
void push_back(const value& t){
if(finish.cur!=finish.last-){
//最后缓冲区上有至少一个备用空间
construct(finish.cur,t); //直接在备用空间上构造元素
++finish.cur; //调整最后缓冲区的使用状态
}
else //最后缓冲区已无元素备用空间或者只有一个元素备用空间
push_back_aux(t);
}接着上面的例子,再在mydeque后面添加一个元素3,由于尾端只存在一个元素的备用空间,所以必须调用push_back_aux,先配置一整块的缓冲区,再添加新的元素,deque状态如下:
push_back_aux()函数内容如下:
//只有最后一个缓冲区只剩一个备用元素空间时才会被调用
template <class T,class Alloc,size_t BufSize>
void deque<T,Alloc,BufSize>::push_back_aux(const value_type& t){
value_type t_copy=t;
reserve_map_at_back(); //若符合某种条件则必须重换一个map
*(finish.node+)=allocate_node(); //配置一个新的节点(缓冲区)
__STL_TRY{
construct(finish.cur,t_copy); //针对标的元素设置
finish.set_node(finish.node+); //改变finish,令其指向新节点
finish.cur=finish.first; //设定finish的状态
}
__STL_UNWIND(deallocate_node(*(finish.node+)));
}接着上面的例子,在mydeque的前端插入99,deque状态如下:
push_front()函数操作如下:
public:
void push_front(const value& t){
if(satrt.cur!=start.first){
//第一缓冲区尚有备用空间
construct(start.cur-,t); //直接在备用空间上构造元素
--start.cur; //调整第一缓冲区的使用状态
}
else //第一缓冲区已无备用空间
push_front_aux(t);
}由上图可知,这里必须调用push_front_aux(),push_front_aux()函数操作如下:
//只有第一个缓冲区只剩一个备用元素空间时才会被调用
template <class T,class Alloc,size_t BufSize>
void deque<T,Alloc,BufSize>::push_back_aux(const value_type& t){
value_type t_copy=t;
reserve_map_at_front(); //若符合某种条件则必须重换一个map
*(start.node-)=allocate_node(); //配置一个新的节点(缓冲区)
__STL_TRY{
start.set_node(start.node-); //改变start,令其指向新节点
start.cur=start.last-; //设定start的状态
construct(start.cur,t_copy); //针对标的元素设值
}
catch(...){
//若成功全部执行,若失败全部执行
start.set_node(start.node+);
start.cur=satrt.first;
deallocate_node(*(start.node-));
throw;
}
}
reserve_map_at_back、reserve_map_at_front
reserve_map_at_back()、reserve_map_at_front()这两个函数会在什么时候调用?答案是它们会在map需要重新整治的时候,也就是map的节点备用空间不足的时候。
reserve_map_at_front()函数操作如下:
void reserve_map_at_front(size_type nodes_to_add=){
if(nodes_to_add>start.node-map) //如果map前端的节点备用空间不足,则必须重新换一个map
reallocate_map(nodes_to_add,true); //配置更大的,拷贝原来的,释放原来的
}reserve_map_at_back()函数操作如下:
void reserve_map_at_back(size_type nodes_to_add=){
if(nodes_to_add+>map_size-(finish.node-map)) //如果map尾端的节点备用空间不足,则必须重新换一个map
reallocate_map(nodes_to_add,false);
}reallocate_map()函数操作如下:
template <class T,class Alloc,size_t BufSize>
void deque<T,Alloc,BufSize>::reallocate_map(size_type nodes_to_add,bool add_at_front){
size_type old_num_nodes=finish.node-start.node+;
size_type new_num_nodes=old_num_nodes+nodes_to_add;
map_pointer new_nstart;
if(map_size>*new_num_nodes){
new_nstart=map+(map_size-new_num_nodes)/+(add_at_front?nodes_to_add:);
if(new_nstart<start.node)
copy(start.node,finish.node+,new_nstart);
else
copy_backward(start.node,finish.node+,new_nstart+old_num_nodes);
}
else{
size_type new_map_size=map_size+max(map_size,node_to_add)+;
//配置一块空间,准备给新map使用
map_pointer new_map=map_allocator::allocte(new_map_size);
new_nstart=new_map+(new_map_size-new_num_nodes)/+(add_at_front?nodes_to_add:);
//把原map内容拷贝过来
copy(start.node,finish.node+,new_nastart);
//释放原map
map_allocator::deallocate(map,map_size);
//设定新map的起始地址与大小
map=new_map;
map_size=new_map_size;
}
//重新设定迭代器start和finish
start.set_node(new_nstart);
finish.set_node(new_nstart+old_num_nodes-);
}
deque源码3(deque的构造与内存、ctor、push_back、push_front)的更多相关文章
- 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_ ...
- deque源码2(deque迭代器、deque的数据结构)
deque源码1(deque概述.deque中的控制器) deque源码2(deque迭代器.deque的数据结构) deque源码3(deque的构造与内存.ctor.push_back.push_ ...
- deque源码1(deque概述、deque中的控制器)
deque源码1(deque概述.deque中的控制器) deque源码2(deque迭代器.deque的数据结构) deque源码3(deque的构造与内存.ctor.push_back.push_ ...
- spark 源码分析之十六 -- Spark内存存储剖析
上篇spark 源码分析之十五 -- Spark内存管理剖析 讲解了Spark的内存管理机制,主要是MemoryManager的内容.跟Spark的内存管理机制最密切相关的就是内存存储,本篇文章主要介 ...
- LRU工程实现源码(一):Redis 内存淘汰策略
目录 内存淘汰是什么?什么时候内存淘汰 内存淘汰策略 Redis中的LRU淘汰算法 源码剖析 第一步:什么时候开始淘汰key 配置读取 检查时机 getMaxmemoryState 第二步:淘汰哪些k ...
- jQuery.buildFragment源码分析以及在构造jQuery对象的作用
这个方法在jQuery源码中比较靠后的位置出现,主要用于两处.1是构造jQuery对象的时候使用 2.是为DOM操作提供底层支持,这也就是为什么先学习它的原因.之前的随笔已经分析过jQuery的构造函 ...
- 手把手带你阅读Mybatis源码(一)构造篇
前言 今天会给大家分享我们常用的持久层框架——MyBatis的工作原理和源码解析,后续会围绕Mybatis框架做一些比较深入的讲解,之后这部分内容会归置到公众号菜单栏:连载中…-框架分析中,欢迎探讨! ...
- Python 源码剖析(六)【内存管理机制】
六.内存管理机制 1.内存管理架构 2.小块空间的内存池 3.循环引用的垃圾收集 4.python中的垃圾收集 1.内存管理架构 Python内存管理机制有两套实现,由编译符号PYMALLOC_DEB ...
- spark 源码分析之十五 -- Spark内存管理剖析
本篇文章主要剖析Spark的内存管理体系. 在上篇文章 spark 源码分析之十四 -- broadcast 是如何实现的?中对存储相关的内容没有做过多的剖析,下面计划先剖析Spark的内存机制,进而 ...
随机推荐
- Intellij IDEA环境配置RestEasy,SpringMVC+RestEasy
在SpringMvc中配置RestEasy,需要以下步骤 1.通过maven导入restEasy所需要的jar包 2.在web.xml文件中添加相应的配置. 3.编写服务. 具体步骤: 1.通过mav ...
- vue框架中的日期组件转换为yyy-mm-dd格式
最近在用vue框架写一个app,这个是用到的日期格式转换,把下面的标准格式转换为字符串连接格式
- Deployment descriptor
部署描述符是JavaEE程序常见的一部分,部署一个Servlet 3 或以上应用程序是一件轻而易举的事.通过Servlet注解,对于不太复杂的应用程序,甚至可以部署没有描述符的Servlet/JSP应 ...
- [转]etcd 启用 https
1, 生成 TLS 秘钥对 2,拷贝密钥对到所有节点 3,配置 etcd 使用证书 4,测试 etcd 是否正常 5,配置 kube-apiserver 使用 CA 连接 etcd 6,测试 kube ...
- 深入理解java虚拟机(一)-----java内存区域以及内存溢出异常
概述 Java语言的一个非常重要的特点就是与平台的无关性.而使用Java虚拟机是实现这一特点的关键.一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码.而引入Java语言虚拟机后,J ...
- docker之tomcat简单部署
将apache-tomcat-8.0.36.tar.gz及jdk-7u79-linux-x64.gz拷贝到创建的tomcat8目录下 在tomcat8目录下创建Dockerfile文件 在Docker ...
- [转]构建高性能MySQL体系
来源:http://www.yunweipai.com/archives/21232.html 构建高性能MySQL系统涵盖从单机.硬件.OS.文件系统.内存到MySQL 本身的配置,以及schema ...
- 排序算法(sorting algorithm) 之 选择排序(selection sort)
https://en.wikipedia.org/wiki/Selection_sort loop1: 4,6,1,3,7 -> 4,6,1,3,7 4,6,1,3,7 -> ,3,7 1 ...
- 【转】像素 Pixel (Picture Element)
原文链接:https://blog.csdn.net/zssureqh/article/details/78768942 1.像素Pixel 讲到概念,首选Wiki百科.当然我说的是英文版Pixel ...
- 与我们息息相关的internet服务(2)---WWW服务
在起步一个公司,从组建的技术上,可能要准备很多东西,其中一个就是我们熟悉的公司网站 网站,在初中,那时浏览一个网页可叫网上冲浪,听起来似乎比洗澡还爽快,可现在这词就是土鳖,网上冲浪火起来主要是应 ...