http://www.chinaaspx.com/archive/VC/7043.htm
本人将源代码粘贴于此,各位有兴趣的网友可以测试一试。
说明:
只要将两个文件加入到你的工程中,并在你的CWinApp派生类中加入如下一句即可:
CPtrManager thePtrManager;
然后,在使用普通指针的地方,用灵巧指针替换即可,假如有一个类test,并有如下应用:
test * ptest=new test;
other code
delete ptest;
现在可这样应用:
auto_ptr<test> ptest= new test;
other code
再不用人为的delete ptest 了,垃圾回收将自动清除,即使你有如下应用:
auto_ptr<test> ptest;
test mytest;
ptest=&mytest;
你也不用担心,灵巧指针也不会误删你在栈中的内存。
只要大家认真帮我测试这段代码到没有 BUG,并对部分算法进行优化和改进,那么,我可以相信:“C++中无垃圾回收”将成为历史。
// PtrManager.h: interface for the CPtrManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_PTRMANAGER_H__BB4B38B5_DA34_11D3_9327_000629377185__INCLUDED_)
#define AFX_PTRMANAGER_H__BB4B38B5_DA34_11D3_9327_000629377185__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Afxmt.h"
class CMySingleLock:public CSingleLock
{
public:
CMySingleLock(CSyncObject* pObject, BOOL bInitialLock = FALSE )
:CSingleLock(pObject,bInitialLock){}
void operator delete(void * p)
{
free(p);
}
void * operator new(size_t size)
{
return malloc(size);
}
};
class CPtr
{
friend class CMark;
public:
int GetPtrSize();
CMutex * GetCMutex();
void * GetPtr();
CPtr();
virtual ~CPtr();
int GetCount();
void AddAutoPtr(void * autoPtr,int AutoMark);
BOOL DeleteAutoPtr(void * autoPtr);
void SetPtr(void * thePtr,int Size,
int mark,int count=0);
void operator delete(void * p)
{
free(p);
}
void * operator new(size_t size)
{
return malloc(size);
}
private:
int m_mark;
int m_count;
void * m_ptr;
int m_size;
CPtrArray AutoPtrArray;
CUIntArray m_AutoMark; file://0 in the stack; >0 =mark
CMutex mutex;
};
class CMark
{
friend class CMarkTable;
public:
CMark(){}
virtual ~CMark(){}
void operator delete(void * p)
{
free(p);
}
void * operator new(size_t size)
{
return malloc(size);
}
void CopyFromCPtr(CPtr* theCPtr);
BOOL bIsNoneInStack();
void Release();
private:
int m_mark;
CPtrArray autoptrArray;
CUIntArray automarkArray;
};
class CMarkTable
{
public:
CMarkTable(){Init();}
virtual ~CMarkTable(){}
void AddCMark(CMark * theCMark);
BOOL FindMark(int mark);
void Init();
void DoLockMark();
private:
CPtrArray CMarkArray;
CPtrArray CLockMarkArray;
void GetLockMark();
BOOL FindLockMark(int mark);
void RemoveUnlockMark();
void RemoveGroup(int automark);
};
class CPtrManager
{
public:
int GetAutoMark(void * ptr);
CPtrManager();
virtual ~CPtrManager();
int GetMarkFromPtr(void * Ptr);
void *MallocPtr(size_t size);
BOOL bCanWrite();
void DeletePtr(int mark,void * Ptr);
void AddPtr(void *Ptr,int PtrSize);
static CPtrManager * GetPtrManager();
CPtr * GetCPtr(void * Ptr,int mark);
private:
CPtrArray m_ptr;
void* pCurrent;
unsigned int m_mark;
CUIntArray m_removed;
BOOL bWrite;
static CPtrManager * p_this;
CMutex mutex;
CMarkTable myMarkTable;
void RemoveLockRes();
void CopyAllMark();
static UINT myThreadProc(LPVOID lparm);
CWinThread* myThread;
void BeginThread()
{ myThread=AfxBeginThread(myThreadProc,this);}
};
class parent_autoptr
{
public:
parent_autoptr()
{thisAutoMark=0;}
virtual ~parent_autoptr(){}
virtual void Release(){}
protected:
int thisAutoMark;
};
template<class T>
class auto_ptr :public parent_autoptr
{
public:
virtual void Release(){Remove();}
auto_ptr()
{mark=0;pointee=0;thisAutoMark=GetAutoMark();}
auto_ptr(auto_ptr<T>&rhs);
auto_ptr(T*ptr);
~auto_ptr(){Remove();}
T*operator->() const;
operator T*();
T&operator*()const;
auto_ptr<T>&operator=(auto_ptr<T>&rhs);
auto_ptr<T>&operator=(T*ptr);
private:
void Remove();
int GetAutoMark();
CMutex *GetCMutex();
void ReadyWrite();
T*pointee;
int mark;
};
template<class T> T* auto_ptr< T>::operator ->()const
{
return pointee;
}
template<class T> void auto_ptr< T>::ReadyWrite()
{
CPtrManager * pMana=CPtrManager::GetPtrManager();
if(pMana)
{
for(;;)
{
if(pMana->bCanWrite())
break;
}
}
}
template<class T> int auto_ptr< T>::GetAutoMark()
{
CPtrManager * pMana=CPtrManager::GetPtrManager();
if(pMana)
{
return pMana->GetAutoMark(this);
}
return 0;
}
template<class T> CMutex* auto_ptr< T>::GetCMutex()
{
CPtrManager * pMana=CPtrManager::GetPtrManager();
if(pMana)
{
CPtr * theCPtr=pMana->GetCPtr(pointee,mark);
if(theCPtr)
return theCPtr->GetCMutex();
}
return NULL;
}
template<class T> void auto_ptr< T>::Remove()
{
CMutex * theMutex=GetCMutex();
if(theMutex)
{
CMySingleLock *pLock=new CMySingleLock(theMutex);
pLock->Lock();
BOOL bDeleteLock=FALSE;
CPtrManager * pMana=CPtrManager::GetPtrManager();
if(pointee&&pMana)
{
CPtr * theCPtr=pMana->GetCPtr(pointee,mark);
if(theCPtr)
{
if(theCPtr->DeleteAutoPtr(this))
{
if(theCPtr->GetCount()==0)
{
pLock->Unlock();
delete pLock;
pMana->DeletePtr(mark,pointee);
bDeleteLock=TRUE;
delete pointee;
}
}
}
else
{
file://User decide to do
}
}
pointee=NULL;
mark=0;
if(!bDeleteLock)
delete pLock;
}
}
template<class T> auto_ptr< T>::operator T*()
{
return pointee;
}
template<class T> T& auto_ptr< T>::operator *()const
{
return *pointee;
}
template<class T> auto_ptr< T>::auto_ptr(auto_ptr<T>&rhs)
{
thisAutoMark=GetAutoMark();
ReadyWrite();
CMutex * theMutex=GetCMutex();
if(theMutex)
{
CSingleLock singleLock(theMutex);
singleLock.Lock();
pointee=rhs.pointee;
mark=rhs.mark;
CPtrManager * pMana=CPtrManager::GetPtrManager();
if(pMana)
{
CPtr* theCPtr=pMana->GetCPtr(pointee,mark);
if(theCPtr)
{
theCPtr->AddAutoPtr(this,thisAutoMark);
}
}
}
}
template<class T> auto_ptr< T>::auto_ptr(T*ptr)
{
thisAutoMark=GetAutoMark();
ReadyWrite();
mark=0;
pointee=ptr;
CPtrManager * pMana=CPtrManager::GetPtrManager();
if(pMana)
{
mark=pMana->GetMarkFromPtr(ptr);
if(mark>0)
{
CPtr* theCPtr=pMana->GetCPtr(pointee,mark);
if(theCPtr)
{
CMutex * theMutex=theCPtr->GetCMutex();
if(theMutex)
{
CSingleLock singleLock(theMutex);
singleLock.Lock();
theCPtr->AddAutoPtr(this,thisAutoMark);
}
}
}
}
}
template<class T>auto_ptr<T>& auto_ptr< T>::operator=(auto_ptr<T>&rhs)
{
if(pointee!=rhs.pointee)
{
ReadyWrite();
Remove();
pointee=rhs.pointee;
mark=rhs.mark;
CMutex * theMutex=GetCMutex();
if(theMutex)
{
CSingleLock singleLock(theMutex);
singleLock.Lock();
CPtrManager * pMana=CPtrManager::GetPtrManager();
if(pMana)
{
CPtr* theCPtr=pMana->GetCPtr(pointee,mark);
if(theCPtr)
{
theCPtr->AddAutoPtr(this,thisAutoMark);
}
}
}
}
return *this;
}
template<class T> auto_ptr<T>&auto_ptr< T>::operator = (T* ptr)
{
if(pointee!=ptr)
{
ReadyWrite();
Remove();
pointee=ptr;
CPtrManager * pMana=CPtrManager::GetPtrManager();
if(pMana)
{
mark=pMana->GetMarkFromPtr(ptr);
if(mark>0)
{
CPtr* theCPtr=pMana->GetCPtr(pointee,mark);
if(theCPtr)
{
CMutex * theMutex=theCPtr->GetCMutex();
if(theMutex)
{
CSingleLock singleLock(theMutex);
singleLock.Lock();
theCPtr->AddAutoPtr(this,thisAutoMark);
}
}
}
}
}
return *this;
}
class test
{
public:
auto_ptr<test> p;
};
#endif // !defined(AFX_PTRMANAGER_H__BB4B38B5_DA34_11D3_9327_000629377185__INCLUDED_)
// PtrManager.cpp: implementation of the CPtrManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "PtrManager.h"
CPtrManager * CPtrManager::p_this=0;
void operator delete(void * p)
{
free(p);
}
void * operator new(size_t size)
{
CPtrManager * pMana=CPtrManager::GetPtrManager();
return pMana->MallocPtr(size);
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPtr::CPtr()
{
m_count=0;
m_mark=0;
m_ptr=0;
m_size=0;
AutoPtrArray.SetSize(0);
m_AutoMark.SetSize(0);
}
CPtr::~CPtr()
{
}
void * CPtr::GetPtr()
{
return m_ptr;
}
void CPtr::AddAutoPtr(void * autoPtr,int AutoMark)
{
int size=AutoPtrArray.GetSize();
AutoPtrArray.SetAtGrow(size,autoPtr);
m_AutoMark.SetAtGrow(size,AutoMark);
m_count++;
}
BOOL CPtr::DeleteAutoPtr(void * autoPtr)
{
int size=AutoPtrArray.GetSize();
for(int i=0;i<size;i++)
{
if(autoPtr==AutoPtrArray[i])
{
AutoPtrArray.RemoveAt(i);
m_AutoMark.RemoveAt(i);
m_count--;
return TRUE;
}
}
return FALSE;
}
int CPtr::GetCount()
{
return m_count;
}
void CPtr::SetPtr(void * thePtr,int Size,int mark,int count)
{
m_ptr=thePtr;
m_mark=mark;
m_size=Size;
m_count=count;
}
CMutex * CPtr::GetCMutex()
{
return &mutex;
}
int CPtr::GetPtrSize()
{
return m_size;
}
// class CPtrManager
CPtrManager::CPtrManager()
{
m_mark=0;
m_ptr.SetSize(1);
m_ptr[0]=0;
m_removed.SetSize(0);
p_this=this;
pCurrent=0;
bWrite=TRUE;
myThread=0;
BeginThread();
}
CPtrManager::~CPtrManager()
{
p_this=0;
if(myThread)
myThread->SuspendThread( );
int size=m_ptr.GetSize();
for(int i=1;i<size;i++)
{
if(m_ptr[i])
{
free(m_ptr[i]);
}
}
}
void CPtrManager::AddPtr(void *Ptr,int PtrSize)
{
CSingleLock singleLock(&mutex);
singleLock.Lock();
int size=0;
if(m_removed.GetSize()==0)
{
size =m_ptr.GetSize();
}
else
{
size=m_removed[0];
m_removed.RemoveAt(0);
}
if(size==0)
size=1;
CPtr * thePtr=new CPtr;
thePtr->SetPtr(Ptr,PtrSize,size);
m_ptr.SetAtGrow(size,thePtr);
pCurrent=Ptr;
m_mark=size;
}
void * CPtrManager::MallocPtr(size_t size)
{
CSingleLock singleLock(&mutex);
singleLock.Lock();
void * p=malloc(size);
if(p)
AddPtr(p,size);
return p;
}
void CPtrManager::DeletePtr(int mark,void*Ptr)
{
if(mark<=0||m_ptr.GetSize()<mark+1)
return ;
CSingleLock singleLock(&mutex);
singleLock.Lock();
if(m_ptr[mark])
{
CPtr * thePtr=(CPtr*)m_ptr[mark];
if(Ptr!=thePtr->GetPtr())
return ;
delete thePtr;
m_ptr[mark]=NULL;
m_removed.Add(mark);
}
}
int CPtrManager::GetMarkFromPtr(void * Ptr)
{
CSingleLock singleLock(&mutex);
singleLock.Lock();
if(pCurrent==Ptr)
return m_mark;
int size=m_ptr.GetSize();
for(int i=1;i<size;i++)
{
if(m_ptr[i]==Ptr)
return i;
}
return NULL;
}
CPtrManager * CPtrManager::GetPtrManager()
{
return p_this;
}
BOOL CPtrManager::bCanWrite()
{
return bWrite;
}
CPtr * CPtrManager::GetCPtr(void * Ptr,int mark)
{
if(!Ptr||mark<=0 || m_ptr.GetSize()<mark+1)
return NULL;
CSingleLock singleLock(&mutex);
singleLock.Lock();
if(m_ptr[mark])
{
CPtr * thePtr=(CPtr*)m_ptr[mark];
if(Ptr!=thePtr->GetPtr())
return NULL;
else
return thePtr;
}
return NULL;
}
int CPtrManager::GetAutoMark(void *ptr)
{
CSingleLock singleLock(&mutex);
singleLock.Lock();
int size =m_ptr.GetSize();
for(int i=1;i<size;i++)
{
CPtr* theCPtr=(CPtr*)m_ptr[i];
if(theCPtr)
{
int ptrFirst=(int)theCPtr->GetPtr();
int ptrEnd=ptrFirst+theCPtr->GetPtrSize();
int p=(int)ptr;
if(p>=ptrFirst&&p<=ptrEnd)
return i;
}
}
return 0;
}
void CPtrManager::RemoveLockRes()
{
CopyAllMark();
myMarkTable.DoLockMark();
}
void CPtrManager::CopyAllMark()
{
CSingleLock singleLock(&mutex);
singleLock.Lock();
CUIntArray theIntArray;
theIntArray.SetSize(0);
int size=m_ptr.GetSize();
for(int i=0;i<size-1;i++)
{
theIntArray.SetAtGrow(i,i+1);
}
bWrite=FALSE;
BOOL bALLCopyed=TRUE;
int TotalWhile=0;
do
{
TotalWhile++;
bALLCopyed=TRUE;
size=theIntArray.GetSize();
for(i=0;i<size;i++)
{
int m=theIntArray[i];
CPtr * theCPtr=(CPtr*)m_ptr[m];
if(theCPtr)
{
CMutex * theMutex;
theMutex=theCPtr->GetCMutex();
if(theMutex)
{
CMySingleLock * theLock;
theLock=new CMySingleLock(theMutex);
if(!theLock->IsLocked())
{
if(theLock->Lock(50))
{
CMark * theMark;
theMark=new CMark();
theMark->CopyFromCPtr(theCPtr);
delete theLock;
myMarkTable.AddCMark(theMark);
theIntArray.RemoveAt(i);
i--;
size--;
}
else
{
delete theLock;
bALLCopyed=FALSE;
}
}
else
{
delete theLock;
bALLCopyed=FALSE;
}
}
}
}
if(TotalWhile>=50)
break;
}while(!bALLCopyed);
bWrite=TRUE;
}
UINT CPtrManager::myThreadProc(LPVOID lparm)
{
CPtrManager* pana=(CPtrManager*)lparm;
if(!pana)
return 0;
Sleep(500);
for(;;)
pana->RemoveLockRes();
return 0;
}
file://begin class CMark
void CMark::CopyFromCPtr(CPtr *theCPtr)
{
if(!theCPtr)
return;
int size=(theCPtr->AutoPtrArray).GetSize();
automarkArray.SetSize(size);
autoptrArray.SetSize(size);
for(int i=0;i<size;i++)
{
automarkArray[i]=(theCPtr->m_AutoMark)[i];
autoptrArray[i]=(theCPtr->AutoPtrArray)[i];
}
m_mark=theCPtr->m_mark;
}
BOOL CMark::bIsNoneInStack()
{
int size=automarkArray.GetSize();
if(size==0)
return FALSE;
for(int i=0;i<size;i++)
{
if(automarkArray[i]<=0)
return FALSE;
}
return TRUE;
}
void CMark::Release()
{
int size=autoptrArray.GetSize();
for(int i=0;i<size;i++)
{
parent_autoptr * thePtr=
(parent_autoptr *)autoptrArray[i];
thePtr->Release();
}
}
file://end Calss CMark
file://begin class CMarkTable
void CMarkTable::AddCMark(CMark * theCMark)
{
if(theCMark)
CMarkArray.Add(theCMark);
}
BOOL CMarkTable::FindMark(int mark)
{
int size=CMarkArray.GetSize();
for(int i=0;i<size;i++)
{
CMark * theMark=(CMark *)CMarkArray[i];
if(theMark)
{
if(mark==theMark->m_mark)
return TRUE;
}
}
return FALSE;
}
void CMarkTable::GetLockMark()
{
CLockMarkArray.SetSize(0);
int size=CMarkArray.GetSize();
for(int i=0;i<size;i++)
{
CMark * theMark=(CMark*)CMarkArray[i];
if(theMark)
{
if(theMark->bIsNoneInStack())
CLockMarkArray.SetAtGrow(i,theMark);
}
}
}
void CMarkTable::RemoveUnlockMark()
{
CUIntArray UnlockMarkArray;
BOOL bNoneRemoveed;
do
{
bNoneRemoveed=TRUE;
UnlockMarkArray.SetSize(0);
int size=CLockMarkArray.GetSize();
for(int i=0;i<size;i++)
{
CMark * theMark=(CMark*)CLockMarkArray[i];
if(theMark)
{
int size1=(theMark->automarkArray).GetSize();
for(int j=0;j<size1;j++)
{
int mark=(theMark->automarkArray)[j];
if(!FindLockMark(mark))
{
UnlockMarkArray.InsertAt(0,i); file://record to remove
bNoneRemoveed=FALSE;
break;
}
}
}
else
{
UnlockMarkArray.InsertAt(0,i);
bNoneRemoveed=FALSE;
}
}
int size2=UnlockMarkArray.GetSize();
for(int k=0;k<size2;k++)
{
int m=UnlockMarkArray[k];
CLockMarkArray.RemoveAt(m);
}
}while(!bNoneRemoveed);
}
BOOL CMarkTable::FindLockMark(int mark)
{
int size=CLockMarkArray.GetSize();
for(int i=0;i<size;i++)
{
CMark * theMark=(CMark *)CLockMarkArray[i];
if(theMark)
{
if(mark==theMark->m_mark)
return TRUE;
}
}
return FALSE;
}
void CMarkTable::RemoveGroup(int automark)
{
int size=CLockMarkArray.GetSize();
for(int i=0;i<size;i++)
{
CMark * theMark=(CMark *)CLockMarkArray[i];
if(theMark)
{
if(automark==theMark->m_mark)
{
CLockMarkArray.RemoveAt(i);
int size2=
(theMark->automarkArray).GetSize();
for(int j=0;j<size2;j++)
{
int auto_mark=
(theMark->automarkArray)[j];
RemoveGroup(auto_mark);
}
break;
}
}
}
}
void CMarkTable::DoLockMark()
{
GetLockMark();
RemoveUnlockMark();
int size=CLockMarkArray.GetSize();
while(size)
{
CMark* theMark=(CMark*)CLockMarkArray[0];
CLockMarkArray.RemoveAt(0);
if(theMark)
{
int size2=
(theMark->automarkArray).GetSize();
for(int i=0;i<size2;i++)
{
int automark=
(theMark->automarkArray)[i];
RemoveGroup(automark);
}
theMark->Release();
}
size=CLockMarkArray.GetSize();
}
Init();
}
void CMarkTable::Init()
{
int size=CMarkArray.GetSize();
for(int i=0;i<size;i++)
{
CMark* theMark=(CMark*)CMarkArray[i];
if(theMark)
delete theMark;
}
CMarkArray.SetSize(0);
CLockMarkArray.SetSize(0);
}
file://end class CMarkTable