对象池的指针版本。池中本质上是一群对象,只构造一次,返回指针。主要支持频繁重建的内存空间不连续的自建结构,如树,链表。
/**//******************************************************************
*名称:PointerPool(指针池)(模板)
*版本号:0.1
*作者:赵耀(中山大学2010级)
*时间:2011.4.11
*简介:
* 对应于对象池,这是一个指针池,用于缓存频繁调用的指针(对象).主要支
* 持频繁重建的树或链表等结构.具有默认构造函数接收一个size_t对象表明指针
* 分块的大小,默认为10.接收的参数如果<=0则会抛出异常invalid_argument.
* public方法:
* T* getPointer(); 从池中返回一个该类型对象的指针;
* void recyclePointer( T* ); 接受需要回收的指针;
* void clear(); 清空池以释放占用的内存;
* bool empty(); 返回池是否为空;
* size_t size(); 返回池中总指针数量;
* size_t remain(); 返回指针池剩余可用指针的数量;
* 注意:
* 使用方法可简单地想成通过两个成员函数来代替new和delete.必须确保分
* 配的指针得到回收!必须确保回收的指针不是外来指针!因为未进行二次初始化,
* 重新分配得到的指针所指对象可能是上一次使用后的残余对象,请进行必要的初
* 话工作.
*
*未完成特性:
* 因为主要支持树,链表等内存空间不连续的结构,所以未实现成数组规模
* 地分配指针的功能.
*
*已知bug:暂无
*
*版权信息:
* 该代码为开源代码,原作者保留其所有权.你可以拷贝,修改,使用该代码,但
* 是请保留必要的版权信息.
******************************************************************/
#ifndef POINTERPOOL_H
#define POINTERPOOL_H
#include <vector>
#include <queue>
#include <stdexcept>
#include <memory>
using namespace std;
template< typename T >
class PointerPool
{
public:
//Create a PointerPool to contain size pointers.
PointerPool( size_t size = kDefaultChunkSize )
throw ( invalid_argument, bad_alloc );
~PointerPool();
//Return a specific pointer to client.
T *getPointer();
//Recycle the pointer that the client doesn't need any more.
void recyclePointer( T* );
//Clear the pool and release the memory.
void clear();
bool empty();
//Return the total number of pointers the pool contains.
size_t size();
//Return the number of pointers remain available.
size_t remain();
protected:
queue< T* > mFreeList;
vector< T* > mAllpointers;//A record of all pointers which help
//to destroy them.
size_t mChunkSize;
static const size_t kDefaultChunkSize = 10;
//Allocate mChunkSize new pointers and add them to the
//mFreeList.
void allocateChunk();
//help the destructor the delete the pointers int the pool.
static void deleteHelper( T* );
private:
//Hide the copy constructor and assignment symbol.
PointerPool( const PointerPool< T > & );
PointerPool< T > &operator=( const PointerPool< T > & );
};
template< typename T >
size_t PointerPool<T>::remain()
{
return mFreeList.size();
}
template< typename T >
bool PointerPool<T>::empty()
{
return remain() == 0;
}
template< typename T >
size_t PointerPool<T>::size()
{
return mChunkSize * mAllpointers.size();
}
template< typename T >
PointerPool<T>::PointerPool( size_t size /**//*= kDefaultChunkSize */ ) throw ( invalid_argument, bad_alloc )
{
if ( size <= 0 )
throw invalid_argument( "chunk size must be positive" );
mChunkSize = size;
allocateChunk();
}
template< typename T >
T *PointerPool<T>::getPointer()
{
if ( mFreeList.empty() )
allocateChunk();
T *ptr = mFreeList.front();
mFreeList.pop();
return ptr;
}
template< typename T >
void PointerPool<T>::clear()
{
for_each( mAllpointers.begin(), mAllpointers.end(), deleteHelper );
mAllpointers.clear();
while ( !mFreeList.empty() )
mFreeList.pop();
}
template< typename T >
void PointerPool<T>::recyclePointer( T *ptr )
{
mFreeList.push( ptr );
}
template< typename T >
void PointerPool<T>::allocateChunk()
{
T* newPointerChunk = new T[ mChunkSize ];
mAllpointers.push_back( newPointerChunk );
for ( int i = 0; i < mChunkSize; i++ )
{
mFreeList.push( &newPointerChunk[i] );
}
}
template< typename T >
void PointerPool<T>::deleteHelper( T *pointerChunk )
{
delete [] pointerChunk;
}
template< typename T >
PointerPool<T>::~PointerPool()
{
for_each( mAllpointers.begin(), mAllpointers.end(), deleteHelper );
}
#endif
以下为测试代码:
#include "PointerPool.h"
#include <iostream>
using namespace std;
class ListNode
{
public:
int value;
ListNode *nextPtr;
ListNode() : value(0), nextPtr(0)
{}
};
int growing()
{
static int numGrouwing = 0;
return numGrouwing++;
}
int main()
{
const int cases = 2;
PointerPool< ListNode > lnPool;
//Make 2 tests.
for ( int i = 0; i < cases; i++ )
{
if ( lnPool.empty() )
cout << "The pool is empty!" << endl;
else
cout << "The pool has " << lnPool.remain()
<< " pointers available" << endl;
//Create the head of a list.
ListNode *start = lnPool.getPointer();
start->value = growing();
ListNode *last = start;
//Complete the list with length of 100.
for ( int j = 1; j < 100; j++ )
{
ListNode *tmp = lnPool.getPointer();
tmp->value = growing();
last->nextPtr = tmp;
last = tmp;
}
//Travel and cout the value of each node.
ListNode *current = start;
while ( current != 0 )
{
cout << current->value << '\t';
current = current->nextPtr;
}
//Recycle all pointers back to the pool.
while ( start != 0 )
{
current = start;
start = start->nextPtr;
lnPool.recyclePointer( current );
}
cout << "The pool has " << lnPool.size() << " pointers"
<< "\n\n";
//Try clear the pool
lnPool.clear();
}
}