스마트 포인터( SmartPtr ) (펌)
C++ 2008. 1. 24. 12:26 |Smart Ptr
#ifndef SMARTPTR_H
#define SMARTPTR_H
template <class T> class SmartPtr;
// IRefCount 참조 횟수 관리를 위한 인터페이스
// 클래스들은 이것을 직접 구현해도 되고, 아니면
// 내부적으로 IRefCount를 구현하고 있는 SmartPtr을 사용해도 된다.
template <class T> class IRefCount {
friend class SmartPtr<T>;
protected:
virtual void AddRef() = 0;
virtual void Release() = 0;
virtual T* GetPtr() const = 0;
};
// IRefCountImpl
// IRefCount의 표준적인 구현
// 이것을 상속하기만 하면 참조 횟수 관리 기능이 생긴다.
// class CMyObject : public IrefCountImpl<CMyObjct> { ... };
// 주의: 개별 클래스가 IRefCount를 꼭 구현할 필요는 없지만,
// 직접 구현함으로써 메모리 단편화를 줄일 수도 있다.
template <class T> class IRefCountImpl
: public IRefCount<T>
{
private:
int m_Count;
protected:
virtual void AddRef() { m_Count++; }
virtual void Release();
{
assert( m_Count>=0);
m_Count--;
if( m_Count<=0 )
{
Destroy();
}
}
virtual T* GetPtr() const { return ( (T*)this ); }
virtual void Destroy() { if(GetPtr()!=NULL) delete GetPtr(); }
IRefCountImpl() { m_Count = 0; }
};
// SmartPtr
template <class T> class SmartPtr
{
private:
IRefCount<T> *m_RefCount;
// RefCounter
// IRefCount를 직접 구현하지 않는 클래스를 위한 내부구현.
// SmartPtr은 이 내부 구현과 클래스 T의 IRefCount 구현중
// 적절한 것ㅇ르 자동적으로 선택한다.
class RefCounter : public IRefCountImpl<T> {
private:
T *m_Ptr;
protected:
virtual T* GetPtr() const { return m_Ptr; }
virtual void Destroy() { delete this; }
public:
RefCounter( T* ptr ) { m_Ptr = ptr; }
virtual ~RefCounter() { IRefCountImpl<T>::Destroy(); }
};
// T가 IRefCount를 구현하지 않았다면 이 메서드가 호출된다.
void Assign( void *ptr )
{
if( ptr==NULL )
Assign( (IRefCount<T> *)NULL );
else
{
Assign( new RefCounter( static_cast<T*>(ptr) ) );
}
}
// T가 IRefCount를 구현하고 있다면 Assign(void *ptr) 대신
// 이 메서드가 호출된다.
// 이를 통해서 메모리 사용이 좀더 최적화된다.
void Assign( IRefCount<T> *refcount )
{
if( refcount != NULL )
refcount->AddRef();
IRefCount<T> *oldref = m_RefCount;
m_RefCount = refcount;
if( oldref!=NULL )
oldref->Release();
}
public:
SmartPtr() { m_RefCount = NULL; }
SmartPtr( T *ptr ) { m_RefCount = NULL; Assign(ptr); }
SmartPtr(const SmartPtr &sp) { m_RefCount = NULL; Assign(sp.m_RefCount); }
virtual ~SmartPtr() { Assign( (IRefCount<T> *)NULL); }
T* GetPtr() const { return (m_RefCount = NULL ) ? NULL : m_RefCount->GetPtr(); }
// 배정 연산자들
SmartPtr& operator = (const SmartPtr &sp) { Assign(sp.m_RefCount); return *this; }
SmartPtr& operator = (T* ptr) { Assign(ptr); return *this; }
// T접근 및 const 변환
T* operator -> () { assert(GetPtr() != NULL); return GetPtr(); }
operator T* () const { return GetPtr(); }
// 기타 편의성 연산자들
bool operator ! () { return GetPtr() == NULL; }
bool operator == (const SmartPtr &sp) { return GetPtr() == sp.GetPtr(); }
bool operator != (const SmartPtr &sp) { return GetPtr() != sp.GetPtr(); }
};
#endif
다음은 템플릿 사용 예
SmartPtr.cpp
#include "stdafx.h"
#include "assert.h"
#include "smartptr.h"
class CMyObject
{
char *name;
public:
CMyObject(char *aname) { name = aname; printf( "create %s\n", name ); }
virtual ~CMyObject() { printf("delete %s\n", name ); }
void print() { printf("print %s\n",name ); }
};
SmartPtr<CMyObject> f1( char *name )
{
return SmartPtr<CMyObject>(new CMyObject(name));
}
void f2( CMyObject *o )
{
printf( " (print from a function) ");
o->print();
}
int main( void )
{
SmartPtr<CMyObject> ptr1(new CMyObject("1")); // 객체 1을 생성
SmartPtr<CMyObject> ptr2 = new CMyObject("2"); // 객체 2을 생성
ptr1 = ptr2; //객체 1을 파괴
ptr2 = f1("3"); // 반환값으로 쓰이는 경우
ptr2 = NULL; // 객체 3을 파괴
f2(ptr1);
// 잘못된 용례
// CMyObject o1;
// ptr1 = &o1; // o1은 스택에 있으므로 이렇게 하면 안된다.
// CMyObject *o2 = new CMyObject;
// ptr1 = o2;
// ptr2 = o2; // CMyObject가 IRefCount를 구현하지 않는 한 이렇게 하면 안된다.
// 대신 ptr1 = ptr2를 사용할 것, 그것이 항상 안전하다.
// int에 대해서도 SmartPtr을 사용할수 있다.
SmartPtr<int> a(new int);
SmartPtr<int> b(new int);
*a = 5;
*b = 6;
// 명시적으로 파괴하지 않아도 메모리가 새지 않는다.
return 0;
}
(펌) : http://blog.naver.com/twofree?Redirect=Log&logNo=21484155