本文说的对象分配器主要是针对一次分配单个对象的对象分配器。
设计上:
(1)单链表管理分配内存:以最大程度合适使用系统内存,减少系统内存碎片又能让系统找到合适的连续内存。
(2)每个链表节点后面连续着的是实用内存。
(3)为了提高访问速度和方便回收,对于单对象的分配器,又把分配的对象的指针放到数组里管理。
(4)分配时每次从数组末尾获取一个对象,并减小数组长度
(5)回收时把指针放到数组末尾。
(6)内存会在分配器析构时全都释放
分配单个对象的对象分配器
template <class T>
class CListAllocator :
protected lib::container::CBList<T*>
{
public:
typedef lib::container::CBList<T*> super;
private:
struct DataBlock
{
DataBlock* pPrev;
}*m_pDataBlock;
//实际上的内存是在类CListAllocator 的链表里,
//分配的内存的类型指针每个都会复制到父类CBList的指针数组m_pData中
public:
enum
{
AllocObjectCountOneTime = 256,
};
//申请属性指针
T* allocObject()
{
T* result;
INT_PTR nCount = super::count();
if ( nCount <= 0 )
{
DataBlock *pBlock = (DataBlock*)malloc(sizeof(DataBlock) + sizeof(T) * AllocObjectCountOneTime);
memset(pBlock, 0, sizeof(DataBlock) + sizeof(T) * AllocObjectCountOneTime);
//将对象指针全部添加到空闲列表中
result = (T*)(pBlock + 1);
if ( super::maxCount() < AllocObjectCountOneTime )
super::reserve(AllocObjectCountOneTime);
for (INT_PTR i=0; i<AllocObjectCountOneTime; ++i)//复制对象指针
{
(*this)[i] = result;
result++;
}
nCount = AllocObjectCountOneTime;
//标记上内存块的上一个内存块
pBlock->pPrev = m_pDataBlock;
m_pDataBlock = pBlock;
}
//返回列表中的最后一个对象
nCount--;
result = (*this)[nCount];
super::trunc(nCount);
return result;
}
//释放一个对象
inline void freeObject(T* pObject)
{
super::add(pObject);
}
//释放并清除所有对象的内存,将使得所有已申请的对象无效!
inline void freeAll()
{
super::empty();
DataBlock *pBlock, *pPrev;
pBlock = m_pDataBlock;
while (pBlock)
{
pPrev = pBlock->pPrev;
free(pBlock);
pBlock = pPrev;
}
m_pDataBlock = NULL;
}
CListAllocator()
{
m_pDataBlock = NULL;
}
~CListAllocator()
{
freeAll();
}
};
自定义列表的实现:
template <typename T>
class CBList
{
public:
typedef CBList<T> ListClass;
protected:
T* m_pData;
INT_PTR m_tMaxCount;
INT_PTR m_tCount;
public:
CBList()
{
m_pData = 0;
m_tMaxCount = 0;
m_tCount = 0;
}
virtual ~CBList()
{
empty();
}
inline INT_PTR count() const { return m_tCount; }
inline INT_PTR maxCount() const { return m_tMaxCount; }
void insert(const INT_PTR index, const T& data)
{
assert( index > -1 && index <= m_tCount );
if ( m_tCount >= m_tMaxCount )
reserve( (m_tMaxCount > 0) ? m_tMaxCount * 2 : 16 );
if ( index < m_tCount )
{
memmove( &m_pData[index + 1], &m_pData[index], sizeof(T) * (m_tCount - index) );
}
m_pData[index] = data;
m_tCount++;
}
INT_PTR add(const T& data)
{
if ( m_tCount >= m_tMaxCount )
reserve( (m_tMaxCount > 0) ? m_tMaxCount * 2 : 16 );
memcpy(&m_pData[m_tCount], &data, sizeof(data));
m_tCount++;
return m_tCount-1;
}
inline const T& get(const INT_PTR index) const
{
assert( index > -1 && index < m_tCount );
return m_pData[index];
}
inline void set(const INT_PTR index, const T &item)
{
assert( index > -1 && index < m_tCount );
m_pData[index] = item;
}
INT_PTR index(const T& data) const
{
INT_PTR i;
for ( i=m_tCount-1; i>-1; --i )
{
if ( m_pData[i] == data )
{
return i;
}
}
return -1;
}
void remove(const INT_PTR index)
{
assert( index > -1 && index < m_tCount );
remove( index, 1 );
}
void remove(const INT_PTR index, const INT_PTR count)
{
assert( index + count <= m_tCount );
if ( count > 0 )
{
memcpy( &m_pData[index], &m_pData[index + count], sizeof(m_pData[0]) * (m_tCount - index - count) );
m_tCount -= count;
}
}
virtual void empty()
{
clear();
m_tMaxCount = 0;
if (m_pData)
{
free( m_pData );
m_pData = 0;
}
}
inline void clear()
{
m_tCount = 0;
}
inline void trunc(const INT_PTR count)
{
assert( count > -1 && count <= m_tMaxCount );
m_tCount = count;
}
virtual void reserve(INT_PTR count)
{
if ( count > m_tCount && count != m_tMaxCount )
{
m_tMaxCount = count;
m_pData = (T*)realloc( m_pData, sizeof(T) * count );
}
}
inline void addList(const CBList<T> &list)
{
addArray((T*)list, list.m_tCount);
}
inline void addArray(T* data, INT_PTR length)
{
if ( m_tCount + length > m_tMaxCount )
reserve(m_tCount + length);
memcpy(&m_pData[m_tCount], data, length * sizeof(T));
m_tCount += length;
}
inline INT_PTR push(const T& data)
{
return add(data);
}
inline T pop()
{
if ( m_tCount > 0 )
{
m_tCount--;
return m_pData[m_tCount];
}
throw "stack was empty";
}
inline operator T* () const { return m_pData; }
};