自由列表:实现为已分配但未构造对象的链表。
策略:预先分配一块原始内存来保存未构造的对象,创建新元素的时候,可以在一个预先分配的对象中构造;
释放元素的时候,将其放回预先分配对象的块中,而不是将内存归还给系统。
operator new将新分配的对象放到自由列表;
operator delete将对象放回自由列表。
template<class T> class CacheObj{
public:
void* operator new(std::size_t);
void operator delete(void*,std::size_t);
virtual ~CacheObj() {}
protected:
T* next;
private:
static void add_to_freelist(T*);
static std::allocator<T> alloc_mem;
static T* freeStore;
static const std::size_t chunk;
};
static成员管理自由列表,用static是因为为所有给定类型的对象维持一个自由列表。
CacheObj的工作只是分配和管理已分配但未构造对象的自由列表
使用CacheObj类,模板形参
template<class Type>
class QueueItem: public CacheObj< QueueItem<Type> >
{
}
QueueItem是从保存QueueItem<Type>类型对象的CacheObj实例派生而来的类模板。
如定义int值的Queue,就从CacheObj<QueueItem<int> >派生QueueItem<int>类。
<pre name="code" class="cpp">template<class T>
void* CacheObj<T>::operator new(size_t sz)
{
if(sz != sizeof(T))
throw std::runtime_error("Wrong size");
if(!freeStore){
T* array = alloc_mem.allocate(chunk);
for(size_t i = 0; i != chunk;++i)
add_to_freelist(&array[i]);
}
T* p = freeStore;
freeStore = freeStore->CacheObj<T>::next;
return p;
}
注意:
T* p = freeStore; //在前,用于返回自由列表的第一个对象的地址
freeStore = freeStore->CacheObj<T>::next; //指针重置为自由列表的下一个元素,返回的对象是未构造的,因为用new来构造对象
template<class T>
void CacheObj<T>::operator delete(void* p, size_t)
{
if(p)
add_to_freelist(static_cast<T*>(p));
}
编译器将对象的地址传给operator delete, 指针的类型必须是void*类型,因此需要强制类型转换。
template<class T>
void CacheObj<T>::add_to_freelist(T* p)
{
p->CacheObj<T>::next = freeStore;
freeStore = p;
}
注:
类型T是派生类型,指针p是指向T类型的,而不是CacheObj类型????CacheObj是作为基类使用。
新插入自由列表的为表头freeStore,只能这么设计吗??
定义静态数据成员
template <class T> allocator<T> CacheObj<T>::alloc_mem;
template <class T> T* CacheObj<T>::freeStore;
template <class T> const size_t CacheObj<T>::chunk = 24;
每个类型使用不同的静态成员来实例化CacheObj类。