GSI

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

Posted by gsi
: