|
相比1.1版,增加了一个OB_Ptr 代理类(proxy classes),用它来操作申请的对象,防止错误delete申请来的对象指针而引起程序崩溃。这个OB_Ptr类在语法上只能默认构造对象,构造的对象只能进行“->”操作或“(* ).”操作或判断是否为Null指针。不能进行拷贝构造,赋值“=”或“delete”等操作,因为这些操作往往容易引起申请的对象泄漏或非法delete指针等错误。
/*************ObjectBuffer1.2****************/
//对象缓冲器类模版,缓冲器预先分配一定数量的对象,当用到时就从缓冲器
//请求,不用时归还缓冲器,采用页链表分配技术使缓冲器理论上无分配上限
enum ObjectBuffer_ERROR
{
ObjectBuffer_ERROR_No,
ObjectBuffer_ERROR_Memory, //内存分配错误
ObjectBuffer_ERROR_NullPointer,//无效对象指针
ObjectBuffer_ERROR_MultipleReturn,//多重归还对象
};
template <typename T>
class ObjectBuffer
{
private:
struct SPage;
public:
//proxy classes
class OB_Ptr
{
public:
friend struct SPage;
OB_Ptr() : m_p( NULL ){}
~OB_Ptr(){}
T* operator->()const{ return m_p; }
T& operator*()const{ return *m_p; }
bool IsNull()const{ return NULL == m_p; }
private:
OB_Ptr( T* p ){}
OB_Ptr(const OB_Ptr& rhs){}
OB_Ptr& operator=(const OB_Ptr& rhs){}
T* m_p;
};
public:
ObjectBuffer();
//ulObjectPage,每页上对象的数量,此值应根据对象大小、使用情况统筹选取,以降低内存占用及提高性能。
ObjectBuffer( unsigned long ulObjectOfPage );
~ObjectBuffer();
//请求一个对象
bool RequestObject( OB_Ptr& ptr );
//归还一个对象(注意:归后ptr为NULL值)。
bool ReturnObject( OB_Ptr& ptr );
//获取错误代码
ObjectBuffer_ERROR GetError()const{ return m_Error; }
enum
{
ObjectOfPage_Min = 16, //每页中对象数量的最小值
};
private:
struct SPage
{
T* m_pObjects; //对象数组
T** m_ppObjectStack; //对象堆,堆中存储的是对象指针
bool* m_pbIdles; //对象的空闲标志
unsigned long m_ulTop; //堆顶,当为0时说明对象已用完
unsigned long m_ulObjectCount; //对象数量
SPage* m_pFrontPage; //前一页指针
SPage* m_pBackPage; //后一页指针
bool m_bMemoryError; //内存分配错误标志
SPage()
{
m_pObjects= NULL; //对象数组
m_ppObjectStack = NULL;//对象堆,堆中存储的是对象指针
m_pbIdles= NULL; //对象的空闲标志
m_ulTop = 0; //堆顶,当为0时说明对象已用完
m_ulObjectCount = 0; //对象数量
m_pFrontPage = NULL; //前一页指针
m_pBackPage = NULL; //后一页指针
m_bMemoryError = false; //内存分配错误标志
m_ulObjectCount = ObjectOfPage_Min;
m_pObjects = new T[ m_ulObjectCount ];
m_ppObjectStack = new T*[ m_ulObjectCount ];
m_pbIdles = new bool[ m_ulObjectCount ];
if( NULL == m_pObjects || NULL == m_ppObjectStack || NULL == m_pbIdles )
{
Release();
m_bMemoryError = true;
return;
}
for( unsigned long i = 0; i < m_ulObjectCount; ++i )
{
m_ppObjectStack[m_ulObjectCount - i - 1] = &m_pObjects;
m_pIdles = true;
}
m_ulTop = m_ulObjectCount;
}
SPage( unsigned long ulObjectOfPage )
{
m_pObjects = NULL; //对象数组
m_ppObjectStack = NULL;//对象堆,堆中存储的是对象指针
m_pbIdles = NULL; //对象的空闲标志
m_ulTop = 0; //堆顶,当为0时说明对象已用完
m_ulObjectCount = ulObjectOfPage; //对象数量
m_pFrontPage = NULL; //前一页指针
m_pBackPage = NULL; //后一页指针
m_bMemoryError = false; //内存分配错误标志
if( m_ulObjectCount < ObjectOfPage_Min )m_ulObjectCount = ObjectOfPage_Min;
m_pObjects = new T[ m_ulObjectCount ];
m_ppObjectStack = new T*[ m_ulObjectCount ];
m_pbIdles = new bool[ m_ulObjectCount ];
if( NULL == m_pObjects || NULL == m_ppObjectStack || NULL == m_pbIdles )
{
Release();
m_bMemoryError = true;
return;
}
for( unsigned long i = 0; i < m_ulObjectCount; ++i )
{
m_ppObjectStack[m_ulObjectCount - i - 1] = &m_pObjects;
m_pbIdles = true;
}
m_ulTop = ulObjectOfPage;
}
~SPage(){ Release(); }
void Release()
{
if( NULL != m_pObjects )delete[] m_pObjects;
if( NULL != m_ppObjectStack )delete[] m_ppObjectStack;
if( NULL != m_pbIdles )delete[] m_pbIdles;
m_pObjects = NULL; //对象数组
m_ppObjectStack = NULL;//对象堆,堆中存储的是对象指针
m_pbIdles= NULL; //对象的空闲标志
m_ulTop = 0; //堆顶,当为0时说明对象已用完
m_ulObjectCount = 0; //对象数量
m_pFrontPage = NULL; //前一页指针
m_pBackPage = NULL; //后一页指针
m_bMemoryError = false; //内存分配错误标志
}
bool IsEmpty(){ return 0 == m_ulTop; }
bool IsFull(){ return m_ulTop == m_ulObjectCount; }
bool IsMember( const OB_Ptr& ptr ){ return ( ( ptr.m_p >= m_pObjects ) && ( ptr.m_p <= &m_pObjects[m_ulObjectCount-1] ) ); }
void RequestObject( OB_Ptr& ptr )
{
--m_ulTop;
m_pbIdles[ m_ppObjectStack[ m_ulTop ] - m_pObjects ] = false;
ptr.m_p = m_ppObjectStack[ m_ulTop ];
}
ObjectBuffer_ERROR ReturnObject( OB_Ptr& ptr )
{
T* pObject = ptr.m_p;
if( ( ( ( int )pObject - ( int )m_pObjects ) % sizeof( T ) ) != 0 )
{
return ObjectBuffer_ERROR_NullPointer;
}
if( IsFull() || m_pbIdles[ pObject - m_pObjects ] )
{
return ObjectBuffer_ERROR_MultipleReturn;
}
m_pbIdles[ pObject - m_pObjects ] = true;
m_ppObjectStack[ m_ulTop ] = pObject;
++m_ulTop;
ptr.m_p = NULL;
return ObjectBuffer_ERROR_No;
}
};
SPage* m_pBeginPage; //开始页
SPage* m_pEndPage; //结束页
SPage* m_pCurrentPage; //当前操作页
unsigned long m_ulPageCount; //页数量
unsigned long m_ulObjectOfPage; //每页中对象的数量
unsigned long m_ulIdleObjectCount; //空闲对象数量
ObjectBuffer_ERROR m_Error; //错误代码
};
//end
//////////////////////////////////
//ObjectBuffer Class template implement
//////////////////////////////////////
template <typename T>
ObjectBuffer<T>::ObjectBuffer()
{
m_pBeginPage = NULL; //开始页
m_pEndPage = NULL; //结束页
m_pCurrentPage = NULL; //当前操作页
m_ulPageCount = 0; //页数量
m_ulObjectOfPage = ObjectOfPage_Min; //每页中对象的数量
m_ulIdleObjectCount = 0; //空闲对象数量
m_Error = ObjectBuffer_ERROR_No; //错误标志
m_pCurrentPage = m_pEndPage = m_pBeginPage = new SPage( m_ulObjectOfPage );
if( NULL == m_pBeginPage || m_pBeginPage->m_bMemoryError )
{
m_Error = ObjectBuffer_ERROR_Memory;
return;
}
m_ulPageCount = 1;
m_ulIdleObjectCount += m_ulObjectOfPage;//空闲对象数量增加一个页面的数量
}
template <typename T>
ObjectBuffer<T>::ObjectBuffer( unsigned long ulObjectOfPage )
{
m_pBeginPage = NULL; //开始页
m_pEndPage = NULL; //结束页
m_pCurrentPage = NULL; //当前操作页
m_ulPageCount = 0; //页数量
m_ulObjectOfPage = ulObjectOfPage; //每页中对象的数量
m_ulIdleObjectCount = 0; //空闲对象数量
m_Error = ObjectBuffer_ERROR_No; //错误标志
if( m_ulObjectOfPage < ObjectOfPage_Min )m_ulObjectOfPage = ObjectOfPage_Min;
m_pCurrentPage = m_pEndPage = m_pBeginPage = new SPage( m_ulObjectOfPage );
if( NULL == m_pBeginPage || m_pBeginPage->m_bMemoryError )
{
m_Error = ObjectBuffer_ERROR_Memory;
return;
}
m_ulPageCount = 1;
m_ulIdleObjectCount += m_ulObjectOfPage;//空闲对象数量增加一个页面的数量
}
template <typename T>
ObjectBuffer<T>::~ObjectBuffer()
{
while( NULL != m_pBeginPage )
{
m_pCurrentPage = m_pBeginPage;
m_pBeginPage = m_pBeginPage->m_pBackPage;
m_pCurrentPage->Release();
delete m_pCurrentPage;
}
m_pBeginPage = NULL; //开始页
m_pEndPage = NULL; //结束页
m_pCurrentPage = NULL; //当前操作页
m_ulPageCount = 0; //页数量
m_ulObjectOfPage = 0; //每页中对象的数量
m_ulIdleObjectCount = 0; //空闲对象数量
m_Error = ObjectBuffer_ERROR_No; //错误标志
}
template <typename T>
bool ObjectBuffer<T>::RequestObject( OB_Ptr& ptr )
{
if( m_Error != ObjectBuffer_ERROR_No )return false;
if( !ptr.IsNull() )
{
if( !ReturnObject( ptr ) )return false;
}
if( NULL == m_pCurrentPage )m_pCurrentPage = m_pBeginPage;
for( unsigned long i = 0; i < m_ulPageCount; ++i )
{
if( !m_pCurrentPage->IsEmpty() )//如果不为空就请求一个对象
{
--m_ulIdleObjectCount; //一个对象成功分配,空闲对象数量减1
m_pCurrentPage->RequestObject( ptr );
return true;
}
if( m_pCurrentPage == m_pEndPage )//如果到了未尾就从头开始
{
m_pCurrentPage = m_pBeginPage;
}
else
{
m_pCurrentPage = m_pCurrentPage->m_pBackPage;
}
}
//如果循环结束还没找到空闲对象,说明页面已经用完,需要分配新页面
SPage* m_pNew = NULL;
m_pNew = new SPage( m_ulObjectOfPage );
if( NULL == m_pNew || m_pNew->m_bMemoryError )
{
m_Error = ObjectBuffer_ERROR_Memory;
return false;
}
m_pNew->m_pFrontPage = m_pEndPage;
m_pEndPage->m_pBackPage = m_pNew;
m_pEndPage = m_pNew;
++m_ulPageCount;
m_pCurrentPage = m_pEndPage;
m_ulIdleObjectCount += m_ulObjectOfPage - 1; //空闲对象数量增加一个页面的数量-1
m_pCurrentPage->RequestObject( ptr );
return true;
}
template <typename T>
bool ObjectBuffer<T>::ReturnObject( ObjectBuffer<T>::OB_Ptr& ptr )
{
if( m_Error != ObjectBuffer_ERROR_No)return false;
if( ptr.IsNull() )
{
m_Error = ObjectBuffer_ERROR_NullPointer;
return false;
}
if( NULL == m_pCurrentPage )m_pCurrentPage = m_pBeginPage;
for( unsigned long i = 0; i < m_ulPageCount; ++i )
{
if( m_pCurrentPage->IsMember( ptr ) )//对象是否属于此页
{
ObjectBuffer_ERROR Ret = ObjectBuffer_ERROR_No;
if( ObjectBuffer_ERROR_No != ( Ret = m_pCurrentPage->ReturnObject( ptr ) ) )
{
m_Error = Ret;
return false;
}
++m_ulIdleObjectCount; //一个对象成功归还,空闲对象数量加1
break;
}
if( m_pCurrentPage == m_pEndPage )//如果到了未尾就从头开始
{
m_pCurrentPage = m_pBeginPage;
}
else
{
m_pCurrentPage = m_pCurrentPage->m_pBackPage;
}
}
//如果空闲对象数量大于2倍页面数量,说明空闲对象太多了,需要释放一些以减少内存占用
if( m_ulIdleObjectCount >= ( m_ulObjectOfPage + m_ulObjectOfPage ) )
{
SPage* pTracker = m_pBeginPage; //用于追踪
SPage* pHandlers = NULL; //用于操作
//遍历页面链表,找出空闲页面并释放
while( NULL != pTracker )
{
if( m_ulIdleObjectCount <= m_ulObjectOfPage )break;
pHandlers = pTracker;
pTracker = pTracker->m_pBackPage;//向后遍历
//如果为空闲页面
if( pHandlers->IsFull() )
{
//既不是开始页面也不是结束页面
if( pHandlers != m_pBeginPage && pHandlers != m_pEndPage )
{
pHandlers->m_pFrontPage->m_pBackPage = pHandlers->m_pBackPage;
pHandlers->m_pBackPage->m_pFrontPage = pHandlers->m_pFrontPage;
}
else
{
//如果是开始页面让开始指针指向下一页面
if( pHandlers == m_pBeginPage )
{
m_pBeginPage = pHandlers->m_pBackPage;//让下一页面作为新的开始页面
m_pBeginPage->m_pFrontPage = NULL;//让新开始页面的前一页面指向空
}
else
{
//如果是结束页面让结束指针指向上一页面
m_pEndPage = pHandlers->m_pFrontPage;//让上一页面作为新的结束页面
m_pEndPage->m_pBackPage = NULL;//让新结束页面的后一页面指向空
}
}
//如果和当前页面相同让当前页面指向下一页面
if( pHandlers == m_pCurrentPage )
{
m_pCurrentPage = pHandlers->m_pBackPage;
if( NULL == m_pCurrentPage )m_pCurrentPage = m_pBeginPage; //如果为NULL重新指向开始页面
}
pHandlers->Release();
delete pHandlers;
--m_ulPageCount;
m_ulIdleObjectCount -= m_ulObjectOfPage;
}
}
}
return true;
}
///////////////////////////////
//end
////////////////////////////////////
用法跟以前没多大差别:
char* ErrorInfo[] = { "ObjectBuffer_ERROR_No——没有错误",
"ObjectBuffer_ERROR_Memory——内存分配错误",
"ObjectBuffer_ERROR_NullPointer——无效对象指针",
"ObjectBuffer_ERROR_MultipleReturn——多重归还对象",
};
const int test_count = 300;
ObjectBuffer<V3D> VecBuff( 400 );
ObjectBuffer<V3D>::OB_Ptr pvs[test_count];
for( int i = 0; i < test_count; i++ )
{
if( !VecBuff.RequestObject( pvs ) || pvs.IsNull() )//申请对象并判断是否为Null指针
{
cout<<ErrorInfo[VecBuff.GetError()]<<endl;
return 0;
}
pvs->x = i*10.0f;
pvs->y = i*i+100.0f; //"->"操作
( *pvs ).z = i*i*i - 5000.0f; //"(* )."操作
}
delete pvs[2]; //这句会引起程序崩溃,但现在编译不会通过。
pvs[1] = new V3D; //这句会引起p[1]原来所指的对象泄漏,还会引起p[1]归还失败,
//但现在编译不会通过。
pvs[0] = pvs[1]; //这句会引起p[0]原来所指的对象泄漏,但现在编译不会通过。
for( i = 0; i < test_count; i++ )
{
if( !VecBuff.ReturnObject( pvs ) )//归还对象
{
cout<<ErrorInfo[VecBuff.GetError()]<<endl;
return 0;
}
}
|
|