首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

SGI STL空间配置器(STL源码剖解)

2012-08-08 
SGI STL空间配置器(STL源码剖析)空间配置器的标准接口(根据STL规范) allocator::value_typeallocator::poi

SGI STL空间配置器(STL源码剖析)

空间配置器的标准接口(根据STL规范)

 

SGI STL空间配置器(STL源码剖解)allocator::value_type
SGI STL空间配置器(STL源码剖解)allocator::pointer
SGI STL空间配置器(STL源码剖解)allocator::const_pointer
SGI STL空间配置器(STL源码剖解)allocator::reference
SGI STL空间配置器(STL源码剖解)allocator::const_reference
SGI STL空间配置器(STL源码剖解)allocator::size_type
SGI STL空间配置器(STL源码剖解)allocator::difference_type
SGI STL空间配置器(STL源码剖解)allocator::rebind //一个嵌套的类模板
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)allocator::allocator()
SGI STL空间配置器(STL源码剖解)allocator::allocator(const allocator&)
SGI STL空间配置器(STL源码剖解)template<class U> allocator::allocator(const allocator<U>&) //泛化的拷贝构造函数 
SGI STL空间配置器(STL源码剖解)allocator::~allocator()
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)pointer allocator::address(reference x) const
SGI STL空间配置器(STL源码剖解)//返回某个对象的地址.  a.address(x) 等于 &x
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)const_pointer allocator::address(const_reference x) const
SGI STL空间配置器(STL源码剖解)//同上. 返回一个const对象的地址
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)pointer allocator::allocate(size_type n, const void* = 0 )
SGI STL空间配置器(STL源码剖解)//分配空间, 足以存储n个T对象
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)void allocator::deallocate(pointer p, size_type n)
SGI STL空间配置器(STL源码剖解)//释放空间
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)size_type allocator::max_size() const
SGI STL空间配置器(STL源码剖解)//返回可成功分配的最大量
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)void allocator::construct(pointer p , const T& x)
SGI STL空间配置器(STL源码剖解)//负责构造 相当于 new ((const void*)p) T(x)
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)void allocator::destroy(pointer p)
SGI STL空间配置器(STL源码剖解)//负责析构 相当于 p->~T()
SGI STL空间配置器(STL源码剖解)

 

——————————————————————————————————————

SGI STL 的配置器与众不同, 名称是alloc而不是allocator, 而且不接受任何参数。

 

SGI STL空间配置器(STL源码剖解)vector<int , std::allocator<int> > iv;   //in VC or CB
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)vector<int , std::alloc > iv;                //in GCC
SGI STL空间配置器(STL源码剖解)

 

但是通常都是使用默认的空间配置器,而SGI STL已经为每一个容器都指定了缺省的空间配置器。所以使用的时候无太大区别。

 

SGI STL空间配置器(STL源码剖解)template<class T, class Alloc = alloc>
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)SGI STL空间配置器(STL源码剖解)class vectorSGI STL空间配置器(STL源码剖解){SGI STL空间配置器(STL源码剖解) SGI STL空间配置器(STL源码剖解)};       //缺省使用alloc
SGI STL空间配置器(STL源码剖解)

 

————————————————————————————————————————

SGI空间配置器分析:

C++的new操作符和delete操作符进行内存配置时,new:先配置内存,然后构造对象。delete:先析构对象,然后释放内存。SGI STL将内存配置、释放内存与构造、析构分开。前者由<stl_alloc.h>中的allocate()和deallocate()负责,后者由<stl_construct.h>中的construct()和destroy()负责。 这两个头文件包含于<memory>中(STL标准规定,配置器定义在memory中)。同时<memory>还包含了一个文件<stl_unitialized.h>,定义了一些全局函数用来填充、复制大块内存数据。

 

1.构造和析构。

构造:

 

SGI STL空间配置器(STL源码剖解)template<class T1, class T2>
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)SGI STL空间配置器(STL源码剖解)inline void construct(T1 *p, const T2& value)SGI STL空间配置器(STL源码剖解){
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)new (p) T1(value);   //此处用到placement new 运算,将初始值设定到指针P所指的地方 
SGI STL空间配置器(STL源码剖解)


PS:placement new运算,并不分配内存,而是将已分配的内存调用构造函数来进行初始化。

析构:

析构函数第一个版本接受一个指针,将指针所指之物删除,可以直接调用析构函数。而第二个版本,接受两个迭代器,将其之间的所有对象全部析构。由于我们不知道这个范围的大小,有时候范围很大而每个对象的析构不是必要的,就会造成浪费。因此需要进行一个判断,根据得到的结果来判断是否需要析构它(判断用到了traits方法)。

下面是最终的析构调用情况,其中__false_type和__ture_type是两个空的struct,只用于标识,使其通过函数重载在编译的时候确定调用哪一个版本。

 

SGI STL空间配置器(STL源码剖解)template<class ForwardIterator>
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)SGI STL空间配置器(STL源码剖解)SGI STL空间配置器(STL源码剖解){
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)for(; first<last; ++first)
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)destroy(&*first);
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)}
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)template<class ForwardIterator> 
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)__destroy_aux(ForwardIterator first, ForwardIterator last, __ture_type)
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)SGI STL空间配置器(STL源码剖解)SGI STL空间配置器(STL源码剖解){}
SGI STL空间配置器(STL源码剖解)

 

 同时这个析构函数对char*和wchar_t*有特化版本:将不调用他们的析构函数。(这是没有必要调用析构函数的例子么?)

2. 空间的配置和释放: std::alloc

std::alloc为了效率,设计了双层级配置器,第一级直接使用C的malloc()和free()。第二级则视配置区块的大小选择配置器,如果区块大,则直接调用第一级,如果区块过小,则采用memory pool 整理的方法。

SGI将其简单的包装了一个接口,simple_alloc类。使其符合STL规格。而在使用的时候全部使用的simple_alloc接口(缺省使用)。

 

第一级配置器:

调用malloc()和realloc(),如果配置不成功,则调用oom_malloc(), oom_realloc()(PS:oom= out of memory)。在oom_XXX的处理时,通过不断调用“内存不足处理例程”,期望在某次调用之后能够分配到。设计“内存不足处理例程”是客户端的责任。(effective C++ 对new-handler的行为有一个条款,还没认真看)

第二级配置器:

由于太多小额的区块会造成内存的碎片,同时也会带来额外的负担,因此通过第二级配置器的分配,适当的将小额内存分配出去。当区块小(<128bytes)的时候,采用内存池管理。第二级配置器维护了16个free-lists,各自管理从8~128bytes的小额区块,每一个区块以8bytes递增(将每一个小额的区块需求上调至8的倍数,以便管理)。每一次需要时候就将适当的内存从free-lists中间拔出来。客户释放后就回收到free-lists中。当需要的free-lists中没有可用的区块的时候,调用refill()函数为free-lists填充新的空间(取自内存池,用chunk_alloc()函数)。内存池的处理十分复杂,看的一头雾水。

 

SGI配置器使用方法:

 

SGI STL空间配置器(STL源码剖解)template <class T, class Alloc = alloc>
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)Class vector
SGI STL空间配置器(STL源码剖解)SGI STL空间配置器(STL源码剖解)SGI STL空间配置器(STL源码剖解){
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)public:
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)       typedef T value_type;
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)       …
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)protected:
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)       typedef siple_alloc<value_type, Alloc> data_allocator;
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)       …
SGI STL空间配置器(STL源码剖解)
SGI STL空间配置器(STL源码剖解)};
SGI STL空间配置器(STL源码剖解)

 

其中第二个template参数接受缺省的alloc,可以是第一级配置器也可以是第二级配置器。SGI STL已经把它设定为第二级配置器。

 

 

3. 内存基本处理工具

在头文件<stl_uninitialized>中,定义了3个全局函数,uninitialized_copy(),uninitialized_fill(),uninitialized_fill_n(). 看到这些名字应该就知道它们是什么作用了,它们负责在已分配好的空间进行构造。这三个函数都具有”commit or rollback”语意。要么构造出所有元素,要么不构造任何东西。

在具体的实现中,这三个函数也用到了traits技法,通过traits萃取出元素的特性,如果是POD(Plain Old Data)型别,说明其拥有trivial ctor/ dtor/ copy/ assignment函数,因此可以使用copy()、fill()、fill_n()等算法,如果不是POD型别就只能够循环调用construct()函数了。这里用到的也是函数重载的方法,和上面destroy用到的方法是一样的。

注意:在unitialized_copy()实现的时候,针对char*和wchar_t*两种型别,可以采用最有效率的memmove()来复制,因此需要两份特化版本。

热点排行