第18章 特殊工具与技术(5)
18.1.7 一个内存分配器基类
需要怎样改进内置库的new和delete函数?一个通用策略是预先分配一块原始内存来保存未构造的对象,创建新元素的时候,可以在一个预先分配的对象中构造;释放元素的时候,将它们放回预先分配的块中,而不是将内存实际返还给系统。这种策略常被称为维持一个自由列表(freelist)。可以将自由列表实现为已分配但未构造的对象的链表。
1. CachedObj
template<class T>
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<T> alloc_mem;
static T *freestore;
static const void std::size_t chunk;
};
template<class T>
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<T> alloc_mem;
static T *freestore;
static const void std::size_t chunk;
};2. 使用CachedObj
template<class T>
class QueueItem1:public CachedObj<QueueItem1<T>>{};
template<class T>
class QueueItem1:public CachedObj<QueueItem1<T>>{};3. 分配怎样工作
QueueItem1<int> *qi=new QueueItem1<int>();
QueueItem1<int> *qi=new QueueItem1<int>();因为我们从CachedObj类派生QueueItem类,任何使用new表达式的分配,都分配并构造一个新的QueueItem对象。每个表达式:
(1)使用 QueueItem<T>::operator new函数从自由列表分配一个对象。
(2)为类型T使用元素类型的复制构造函数,在该内存中构造一个对象。
类似地,当像delete pt;这样删除一个QueueItem指针的时候,运行QueueItem析构函数清除pt指向的对象,并调用该类的operator delete,将元素所用的内存放回自由列表。
4. 定义operator new
template<class T>
void *CachedObj<T>::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<T>::next;
return p;
}
template<class T>
void *CachedObj<T>::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<T>::next;
return p;
}5. 定义operator delete
operator delete成员只负责管理内存,在析构函数中已经清楚了对象本身,delete表达式在调用operator delete之前调用析构函数。它调用add_to_freelist成员将被删除对象放回自由列表。
template<class T>
void CachedObj<T>::operator delete(void* p, size_t){
if(p!=0)
add_to_freelist(static_cast<T*>(p));
}
template<class T>
void CachedObj<T>::operator delete(void* p, size_t){
if(p!=0)
add_to_freelist(static_cast<T*>(p));
}6. add_to_freelist成员
template<class T>
void CachedObj<T>::add_to_freelist(T *p){
p->CachedObj<T>::next=freestore;
freestore=p;
}
template<class T>
void CachedObj<T>::add_to_freelist(T *p){
p->CachedObj<T>::next=freestore;
freestore=p;
}为了避免任何与派生类中定义的成员可能的冲突,显式指定我们正在给基类成员next赋值。
7. 定义静态数据成员
template<class T>
std::allocator<T> CachedObj<T>::alloc_mem;
template<class T>
T *CachedObj<T>::freestore=0;
template<class T>
const std::size_t CachedObj<T>::chunk=24;
摘自 xufei96的专栏
补充:软件开发 , C++ ,