空间配置器的标准接口(根据STL规范)
allocator::value_type
allocator::pointer
allocator::const_pointer
allocator::reference
allocator::const_reference
allocator::size_type
allocator::difference_type
allocator::rebind // 一个嵌套的类模板
allocator::allocator()
allocator::allocator( const allocator & )
template allocator::allocator( const allocator & ) // 泛化的拷贝构造函数
allocator:: ~ allocator()
pointer allocator::address(reference x) const
// 返回某个对象的地址. a.address(x) 等于 &x
const_pointer allocator::address(const_reference x) const
// 同上. 返回一个const对象的地址
pointer allocator::allocate(size_type n, const void * = 0 )
// 分配空间, 足以存储n个T对象
void allocator::deallocate(pointer p, size_type n)
// 释放空间
size_type allocator::max_size() const
// 返回可成功分配的最大量
void allocator::construct(pointer p , const T & x)
// 负责构造 相当于 new ((const void*)p) T(x)
void allocator::destroy(pointer p)
// 负责析构 相当于 p->~T()
——————————————————————————————————————
SGI STL 的配置器与众不同, 名称是alloc而不是allocator, 而且不接受任何参数。
vector > iv; // in VC or CB
vector iv; // in GCC
但是通常都是使用默认的空间配置器,而SGI STL已经为每一个容器都指定了缺省的空间配置器。所以使用的时候无太大区别。
template
class vector { } ; // 缺省使用alloc
————————————————————————————————————————
SGI空间配置器分析:
C++的new操作符和delete操作符进行内存配置时,new:先配置内存,然后构造对象。delete:先析构对象,然后释放内存。SGI STL将内存配置、释放内存与构造、析构分开。前者由中的allocate()和deallocate()负责,后者由中的construct()和destroy()负责。 这两个头文件包含于中(STL标准规定,配置器定义在memory中)。同时还包含了一个文件,定义了一些全局函数用来填充、复制大块内存数据。
1.构造和析构。
构造:
template
inline void construct(T1 * p, const T2 & value) {
new (p) T1(value); //此处用到placement new 运算,将初始值设定到指针P所指的地方
PS:placement new运算,并不分配内存,而是将已分配的内存调用构造函数来进行初始化。
析构:
析构函数第一个版本接受一个指针,将指针所指之物删除,可以直接调用析构函数。而第二个版本,接受两个迭代器,将其之间的所有对象全部析构。由于我们不知道这个范围的大小,有时候范围很大而每个对象的析构不是必要的,就会造成浪费。因此需要进行一个判断,根据得到的结果来判断是否需要析构它(判断用到了traits方法)。
下面是最终的析构调用情况,其中__false_type和__ture_type是两个空的struct,只用于标识,使其通过函数重载在编译的时候确定调用哪一个版本。
template
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
{
for(; first
__destroy_aux(ForwardIterator first, ForwardIterator last, __ture_type)
{}
同时这个析构函数对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的行为有一个条款,还没认真看)
第二级配置器:
由于太多小额的区块会造成内存的碎片,同时也会带来额外的负担,因此通过第二级配置器的分配,适当的将小额内存分配出去。当区块小(
SGI配置器使用方法:
template
Class vector
{
public:
typedef T value_type;
…
protected:
typedef siple_alloc data_allocator;
…
} ;
其中第二个template参数接受缺省的alloc,可以是第一级配置器也可以是第二级配置器。SGI STL已经把它设定为第二级配置器。
3. 内存基本处理工具
在头文件中,定义了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()来复制,因此需要两份特化版本。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: 【从0开始编写webserver·基础篇#03】TinyWeb源码阅读,还是得看看靠谱的项目
【前言】 之前通过看书、看视频和博客拼凑了一个webserver,然后有一段时间没有继续整这个项目 现在在去看之前的代码,真的是相当之简陋,而且代码设计得很混乱,我认为没有必要继续在屎堆上修改了,于是开始阅读别人的较为规范的开源实现 目的是尝试理解一个可用级别…