第18章 特殊工具与技术(5)

2014-11-24 12:24:45 · 作者: · 浏览: 3

18.1.7 一个内存分配器基类

需要怎样改进内置库的new和delete函数?一个通用策略是预先分配一块原始内存来保存未构造的对象,创建新元素的时候,可以在一个预先分配的对象中构造;释放元素的时候,将它们放回预先分配的块中,而不是将内存实际返还给系统。这种策略常被称为维持一个自由列表(freelist)。可以将自由列表实现为已分配但未构造的对象的链表。

1. CachedObj


template
class CachedObj{
public:
void *operator new(size_t);
void operator delete(void*,size_t);
virtual ~CachedObj(){}
protected:
T *next;
private:
static void add_to_freelist(T*);
static std::allocator alloc_mem;
static T *freestore;
static const void std::size_t chunk;
};
template
class CachedObj{
public:
void *operator new(size_t);
void operator delete(void*,size_t);
virtual ~CachedObj(){}
protected:
T *next;
private:
static void add_to_freelist(T*);
static std::allocator alloc_mem;
static T *freestore;
static const void std::size_t chunk;
};2. 使用CachedObj


template
class QueueItem1:public CachedObj>{};
template
class QueueItem1:public CachedObj>{};3. 分配怎样工作


QueueItem1 *qi=new QueueItem1();
QueueItem1 *qi=new QueueItem1();因为我们从CachedObj类派生QueueItem类,任何使用new表达式的分配,都分配并构造一个新的QueueItem对象。每个表达式:

(1)使用 QueueItem::operator new函数从自由列表分配一个对象。

(2)为类型T使用元素类型的复制构造函数,在该内存中构造一个对象。

类似地,当像delete pt;这样删除一个QueueItem指针的时候,运行QueueItem析构函数清除pt指向的对象,并调用该类的operator delete,将元素所用的内存放回自由列表。

4. 定义operator new


template
void *CachedObj::operator new(size_t sz){
if(sz!=sizeof(T))
throw std::runtime_error("CachedObj:wrong size object in operator new");
if(!freestore){
T *arr=alloc_mem.allocate(chunk);
for(size_t i=0;i!=chunk;++i)
add_to_freelist(&arr[i]);
}
T *p=freestore;
freestore=freestore->CachedObj::next;
return p;
}
template
void *CachedObj::operator new(size_t sz){
if(sz!=sizeof(T))
throw std::runtime_error("CachedObj:wrong size object in operator new");
if(!freestore){
T *arr=alloc_mem.allocate(chunk);
for(size_t i=0;i!=chunk;++i)
add_to_freelist(&arr[i]);
}
T *p=freestore;
freestore=freestore->CachedObj::next;
return p;
}5. 定义operator delete

operator delete成员只负责管理内存,在析构函数中已经清楚了对象本身,delete表达式在调用operator delete之前调用析构函数。它调用add_to_freelist成员将被删除对象放回自由列表。


template
void CachedObj::operator delete(void* p, size_t){
if(p!=0)
add_to_freelist(static_cast(p));
}
template
void CachedObj::operator delete(void* p, size_t){
if(p!=0)
add_to_freelist(static_cast(p));
}6. add_to_freelist成员


template
void CachedObj::add_to_freelist(T *p){
p->CachedObj::next=freestore;
freestore=p;
}
template
void CachedObj::add_to_freelist(T *p){
p->CachedObj::next=freestore;
freestore=p;
}为了避免任何与派生类中定义的成员可能的冲突,显式指定我们正在给基类成员next赋值。

7. 定义静态数据成员


template
std::allocator CachedObj::alloc_mem;

template
T *CachedObj::freestore=0;

template
const std::size_t CachedObj::chunk=24;

摘自 xufei96的专栏