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的專欄