Ch2 空间配置器(allocator) ---笔记
2.1 空间配置器的标准接口
allocator的必要接口:
allocator::value_type
allocator::pointer
allocator::const_pointer
allocator::reference
allocator::const_reference
allocator::size_type
allocator::difference_type //一个嵌套的class template(类模板),
//class rebind<U>拥有唯一成员other(一个typedef,代表allocator<U>)
allocator::rebind //默认的构造函数
allocator::allocator() //copy constructor(复制构造器)
allocator::allocator(const allocator&) //泛化的copy constructor
template <class U>allocator::allocator(const allocator<U>&) //析构函数
allocator::~allocator() //返回某个对象的地址。算式a.address(x)等同于&x
pointer allocator::address(reference x) cosnt //返回某个cosnt对象的地址。算式a.address(x)等同于&x
const_pointer allocator::address(const_reference x) const //配置空间,足以存储n个T对象。
//第二个参数是提示。实现上可能会利用它来增进区域性(locality),或完全忽略之
pointer allocator::allocate(size_type n,const void*=0) //归还先前配置的空间
void allocator::deallocate(pointer p,size_type n) //返回可成功配置的最大量
size_type allocator::max_size() const //等同于new((void*) p) T(x)
void allocator::construct(pointer p,const T& x) //等同于p->~T()
void allocator::destroy(pointer p)
2.2 具备次配置力(sub-allocation)的SGI空间配置器
SGI STL的配置器名称是alloc,而非allocator,与标准规范不同,且不接受任何参数。
2.2.1 SGI标准的空间配置器,std::allocator
SGI中也定义有一个符合部分标准,名为allocator的配置器,但该配置器没有被全面使用,而只是把C++的::operator new和::operator delete做一层薄薄的包装而已。
2.2.2 SGI特殊的空间配置器,std::alloc
配置器定义于<memory>中,SGI <memory>内包含:
//定义了全局函数construct()和destroy(),负责对象的构造和析构
#include <stl_construct.h> //定义了一、二级配置器,彼此合作。配置器名为alloc。
#include <stl_alloc.h> //定义了一些用来填充(fill)或复制(copy)大块内存数据的函数,
//如:un_initialized_copy()
// un_initialized_fill()
// un_initialized_fill_n()
//这些函数不属于配置器的范畴,但与对象初值设置有关。
//对于容器的大规模元素初值设置很有帮助
//最差情况下,会调用construct(),
//最佳情况下,会使用C标准函数memmove()直接进行内存数据的移动。
#include <stl_uninitialized.h>
2.2.3 构造和析构基本工具:construct()和destroy()
/*<stl_construct.h>的部分代码 */
#include <new.h> //欲使用placement new,需先包含此文件 template <class T1,class T2>
inline void construct(T1* p, const T2& value){
new(p) T1(value); //placemnt new; 调用T1::T1(value);
} //destroy()第一版本,接受一个指针
template <class T>
inline void destroy(T* pointer){
pointer->~T(); //调用dtor ~T()
} //destroy()第二版本,接受两个迭代器,此函数设法找出元素的数字型别(value type),
//进而利用__type_traits<> 求取最适当措施
template <class ForwardIterator>
inline void destroy(ForwardIterator first,ForwardIterator last){
__destroy(first,last,value_type(first));
} //判断元素的数值型别(value type)是否有trivial destructor
template <class ForwardIterator, class T>
inline void __destroy(ForwardIterator first,ForwardIterator last,T*){
typedef typename __type_traits<t>::has_trivial_destructor trivial_destructor;
__destroy_aux(first,last,trivial_destructor());
} //如果元素的value type有non-trivial destructor
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator first,ForwardIterator last,__false_type){
for( ;first<last;++first)
destroy(&*first);
} //如果元素的value type有trivial(无价值的) destructor
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator first,ForwardIterator last,__true_type){} //destroy()第二版本针对迭代器为char*和wchar_t*的特化版
inline void destroy(char*,char*){}
inline void destroy(wchar_t*,wchar_t*){}
2.2.4 空间的配置与释放,std::alloc
对象构造前的空间配置和对象构造后的空间释放,由<stl_alloc.h>负责,SGI以malloc()和free()完成内存的配置和释放。
由于小型区块可能造成内存碎片问题,所以SGI设计了双层级配置器:
/*只开放第一级,还是同时开放第二级配置器,取决于__USE_MALLOC是否被定义*/
#ifdef __USE_MALLOC
//…
typedef __malloc_alloc_template<0> malloc_alloc;
typedef malloc_alloc alloc; //令alloc为第一级配置器
#else
//…
//令alloc为第二级配置器
typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;
#endif /*!__USE_MALLOC */ /**SGI STL 第一级配置器
*1.allocate()直接使用malloc(),deallocate()直接使用free();
*2.模拟C++的set_new_handler()以处理内存不足的状况。*/
template<int inst>
class __malloc_alloc_template { ... } /**SGI STL 第二级配置器
*1.维护16个自由链表(free lists),负责16中小型区块的次配置能力,
* 内存池(memory pool)以malloc()配置而得;
*2.如果需求区块大于128bytes(内存不足),则转调用第一级配置器。*/
template <bool threads, int inst>
calss __default_alloc_template { ... }SGI还为配置器(无论第一还是第二级)包装了一个能够符合STL 规格的接口:
template<class T, class Alloc>
class simple_alloc{
public:
static T *allocate(size_t n){
return 0 == n? 0: (T*)Alloc::allocate(n*sizeof(T)); }
static T *allocate(void){
return (T*)Alloc::allocate(sizeof(T)); }
static void deallocate(T *p, size_t n){
if(0!=n) Alloc::deallocate(p, n*sizeof(T));
static void deallocate(T *p){
Alloc::deallocate(p, sizeof(T)); }
};
2.2.7 空间配置函数allocate()
__default_alloc_template拥有配置器的标准接口函数allocate()。
//n must be > 0
static void * allocate(size_t n){
obj * volatile * my_free_list;
obj * result;
//大于128就调用第一级配置器
if(n > (size_t) __MAX_BYTES){
return (malloc_alloc::allocate(n));
}
//寻找16个free lists中适当的一个
my_free_list=free_list+FREELIST_INDEX(n);
result=*my_free_list;
if(result==0){
//没找到可用的free list,准备重新填充free list
void *r=refill(ROUND_UP(n));
return r;
}
//调整free list
*my_free_list=result->free_list_link;
return (result);
}
2.2.8 空间释放函数deallocate()
__default_alloc_template拥有配置器的标准接口函数deallocate()。
//p 不可以是0
static void deallocate(void *p,size_t n){
obj *q=(obj *) p;
obj * volatile * my_free_list;
//大于128就调用第一级配置器
if(n> (size_t) __MAX_BYTES){
malloc_alloc::deallocate(p, n);
return;
}
//寻找对应的free list
my_free_list=free_list+FREELIST_INDEX(n);
//调整free list,回收区块
q->free_list_link=*my_free_list;
*my_free_list=q;
}
2.2.9 重新填充free lists
当allocate()函数发现free list中没有可用区块了时,就调用refill(),准备为free list重新填充空间。
新的空间将取自内存池(经由chunk_alloc()完成)。
缺省取得20个新节点(新区块),但万一内存池空间不足,获得的节点数(区块数)可能小于20:
//返回一个大小为n的对象,并且有时候会为适当的free list增加节点
//假设n已经适当上调至8的倍数
template <bool threads, int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n){
int nobjs=20;
//调用chunk_alloc(),尝试取得nobjs个区块作为free list的新节点
//注意参数nobjs是PASS BY REFERENCE
char * chunk=chunk_alloc(n, nobjs);
obj * volatile * my_free_list;
obj * result;
obj * current_obj, *next_obj;
int i; //如果只获得一个区块,这个区块就分配给调用者用,free list无新节点
if(1 == nobjs) return (chunk);
//否则准备调整free list,纳入新节点
my_free_list=free_list+FREELIST_INDEX(n); //以下在chunk空间内建立free list
result=(obj *)chunk; //这一块准备返回给客端
//以下导引free list指向新配置的空间(取自内存池)
*my_free_list=next_obj=(obj *)(chunk+n);
//以下将free list的各节点串接起来
for( i=1; ; i++){ //从1开始,因为第0个将返回给客端
current_obj=next_obj;
next_obj=(obj *)((char *)next_obj+n);
if(nobjs-1 == i){
current_obj->free_list_link=0;
break;
}else{
current_obj->free_list_link=next_obj;
}
}
return (result);
}
2.2.10 内存池(memory pool)
上一小节提到的chunk_alloc()函数以end_free – start_free来判断内存池的水量。
如果水量充足,就直接调出20个区块返回给free list。
如果水量不足以提供20个区块,但还足够供应一个(含)以上的区块,就拨出这不足20个区块的空间出去。这时候其pass by reference的nobjs参数将被修改为实际能够供应的区块数。
如果内存池连一个区块空间都无法供应,便需利用malloc()从heap中配置内存,为内存池注入源头活水以应付需求。
新水量的大小为需求量的两倍,再加上一个随着配置次数增加而愈来愈大的附加量。
若整个system heap 空间都不够(以至无法为内存池注入源头活水),则malloc()失败,chunk_alloc()就四处寻找有无“尚有为用区块,且区块够大”的free lists。找到了就挖一块交出,找不到就调用第一级配置器。
第一级配置器其实也是使用malloc()来配置内存,但它有out-of-memory处理机制,或许有机会释放其他内存拿来此处使用。如果可以,就成功,否则发出bad_alloc异常。
2.3 内存基本处理工具
STL作用于未初始化空间上的五个全局函数——用于构造的construct()、用于析构的destroy(),以及uninitialized_copy(),uninitialized_fill(),uninitialized_fill_n()分别对应高层次函数copy()、fill()、fill_n()。
2.3.1 uninitialized_copy
uninitialized_copy()使我们能够将内存的配置与对象的构造行为分离开来,
如果作为输出目的地的[result,result+(last-first)) 范围内的每一个迭代器都指向未初始化区域,
则uninitialized_copy()会使用copy constructor,给身为输入来源之[first, last)范围内的每一个对象产生一份复制品,放进输出范围中。
2.3.2 uninitialized_fill
uninitialized_fill()使我们能够将内存的配置与对象的构造行为分离开来,
如果[first, last)范围内的每个迭代器都指向未初始化的内存,
那么uninitialized_fill()会在该范围内产生x(该函数的第三个参数 const T& x)的复制品。
2.3.3 uninitialized_fill_n
uninitialized_fill()使我们能够将内存的配置与对象的构造行为分离开来。
它会为指定范围内的所有元素设定相同的初值。
如果[first, first+n)范围内的每一个迭代器都指向未初始化的内存,
那么uninitialized_fill_n()会调用copy constructor,在该范围内产生x(该函数的第三个参数 const T& x)的复制品。
这三个函数的进行逻辑是,萃取出迭代器first(uninitialized_copy函数是取出result)的value type,然后判断该型别是否为POD型别:
—— 如果是POD型别,则执行其对应的高层次函数(分别是copy(),fill(),fill_n());
——如果不是,则只能一个一个元素地构造(遍历每个迭代器,调用construct()),无法批量进行。
*POD——Plain Old Data,即标量型别(scalar types)或传统的C struct型别
——故POD型别必然拥有trivial ctor/tor/copy/assignment函数
——因此可以对POD型别采用最有效率的初值填写手法,而对非POD型别只好采用最保险安全的做法。
Ch2 空间配置器(allocator) ---笔记的更多相关文章
- STL的空间配置器std_alloc 笔记
STL的空间配置器std_alloc 笔记 C++的内存分配基本操作是 ::operator new(),内存释放是 ::operator delete(),这里个全局函数相当于C的malloc和fr ...
- C++ 空间配置器(allocator)
C++ 空间配置器(allocator) 在STL中,Memory Allocator 处于最底层的位置,为一切的 Container 提供存储服务,是一切其他组件的基石.对于一般使用 STL 的用户 ...
- STL学习笔记:空间配置器allocator
allocator必要接口: allocator::value_type allocator::pointer allocator::const_pointer allocator::referenc ...
- 《STL源码剖析》chapter2空间配置器allocator
为什么不说allocator是内存配置器而说是空间配置器,因为空间不一定是内存,也可以是磁盘或其他辅助介质.是的,你可以写一个allocator,直接向硬盘取空间.sgi stl提供的配置器,配置的对 ...
- STL源码剖析 — 空间配置器(allocator)
前言 以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象都存放在容器之中. 你完全可以实现一个直接向硬件存取空间的allocator. 下面介绍的是SGI STL提供的配 ...
- STL源码剖析——空间配置器Allocator#1 构造与析构
以STL的运用角度而言,空间配置器是最不需要介绍的东西,因为它扮演的是幕后的角色,隐藏在一切容器的背后默默工作.但以STL的实现角度而言,最应该首先介绍的就是空间配置器,因为这是这是容器展开一切运作的 ...
- C++ STL学习之 空间配置器(allocator)
众所周知,一般情况下,一个程序包括数据结构和相应的算法,而数据结构作为存储数据的组织形式,与内存空间有着密切的联系. 在C++ STL中,空间配置器便是用来实现内存空间(一般是内存,也可以是硬盘等空间 ...
- STL之空间配置器allocator
摘要 C++STL的空间配置器将内存的分配.释放,对象的构造.析构都分开执行,内存分配由alloc::allocate()负责,内存的释放由alloc::deallocate()负责:对象的构造由:: ...
- STL源码剖析——空间配置器Allocator#2 一/二级空间配置器
上节学习了内存配置后的对象构造行为和内存释放前的对象析构行为,在这一节来学习内存的配置与释放. C++的内存配置基本操作是::operator new(),而释放基本操作是::operator del ...
随机推荐
- Xamarin Mono 环境搭建
Xamarin Mono 环境搭建(使用Visual Studio 2013 开发android 和 ios ) 本文主要介绍Xamarin结合VS2013来开发Android应用程序,主要会介绍Mo ...
- Value Object(值对象)如何使用 EF 进行正确映射
DDD 领域驱动设计-Value Object(值对象)如何使用 EF 进行正确映射 写在前面 首先,这篇博文是用博客园新发布的 MarkDown编辑器 编写的,这也是我第一次使用,语法也不是很熟悉, ...
- 修改servu数据库密码 servu加密方式
项目要求可以有用户自行修改servu密码.servu可以通过odbc访问access\mysql\sqlserver数据库.我们直接通过创建web来修改就可以了. 不过问题来了,密码是加密的...通过 ...
- MVC之验证
MVC之验证 有时候我觉得,很多人将一个具体的技术细节写的那么复杂,我觉得没有必要,搞得很多人一头雾水的,你能教会别人用就成了,具体的细节可以去查MSDN什么的,套用爱因斯坦的名言:能在网上查到的就不 ...
- 回车tab切换
//event表示事件对象,keyCode表示键值,srcElement事件源 function changeCommand(){ //如果按下的是回车,并且不是提交按钮,不是重置按钮,则回车认为是t ...
- [置顶] 纯手工打造漂亮的垂直时间轴,使用最简单的HTML+CSS+JQUERY完成100个版本更新记录的华丽转身!
前言 FineUI控件库发展至今已经有 5 个年头,目前论坛注册的QQ会员 5000 多人,捐赠用户 500 多人(捐赠用户转化率达到10%以上,在国内开源领域相信这是一个梦幻数字!也足以证明Fine ...
- Struts2的拦截器
拦截器的作用: 拦截器可以动态地拦截发送到指定Action的请求,通过拦截器机制,可以载Action执行的前后插入某些代码,植入我们的逻辑思维. 拦截器的实现原理: 拦截器通过代理的方式来调用,通过动 ...
- jquery水印插件:placeholder
jquery水印插件:placeholder 有的浏览器支持html5的水印placeholder(如Crome,firefox,ie10+),有的不支持html5的placeholder(ie9,i ...
- NuGet安装及简单使用
通过Visual Studio安装NuGet 直接下载并安装NuGet 一.通过Visual Studio安装NuGet 打开Visual Studio扩展管理器 2.选择联机库,并在搜索中写入NuG ...
- Asycn/Await 异步编程初窥(二)
经过总过4天的学习和实践,做完了 WinForm 下 .Net 4.5 的基本异步应用,实现了一个 Http 协议下载的测试程序,为以后使用 .Net 4.5 积累知识和经验.这个小程序完成这样几个作 ...