shared_ptrの実装3

前回の続き
では、実際に参照カウンタ式のスマートポインタを作ってみましょう。

参照カウンタを追加

たとえば以下のような場合、new intの実体と参照数が共有されるので、参照カウンタも動的に作らないといけませんね。

    shared_ptr< int > a( new int( 100 ) ); //参照カウンタ=1
    shared_ptr< int > b = a;               //参照カウンタ=2


template < typename T >
class shared_ptr
{
private:
    T* ptr;
    int* count;		//reference counter

public:
    shared_ptr()
        : ptr( 0 )
        , count( 0 )
    {}
    shared_ptr( T* ptr )
        : ptr( ptr )
        , count( new int( 1 ) )
    {}

    ...省略
};
  • コンストラクタで生のポインタを受け取ったとき、参照数を1として参照カウンタを生成

boostの場合、shared_countという参照カウンタクラスを使っていますが、今回は使わない方向で。

参照数のインクリメント、デクリメント

コピーコンストラクタで参照数をインクリメント、デストラクタでデクリメントしましょう。
デクリメントの結果、0になっていればshared_ptrの参照先をdeleteし、参照カウンタもdeleteします。

template < typename T >
class shared_ptr
{
public:
    ...略

    shared_ptr( shared_ptr const& p )
        : ptr( p.ptr )
        , count( p.count )
    {
        if( count )
            ++ ( *count );
    }

    ~shared_ptr()
    {
        if( count )
        {
            if( --( *count ) == 0 )
            {
                delete ptr;
                delete count;
            }
        }
    }
    ...略
};

動作結果を確認してみましょう。

    {
        shared_ptr< int > a( new int( 100 ) ); //参照カウンタ=1
        {
            shared_ptr< int > b = a;           //参照カウンタ=2
        }                                      //参照カウンタ=1
    }                                          //参照カウンタ=0

問題ないですね。

operator=

以下のように既存のshared_ptrにもコピーできるようにoperator=も追加しましょう。

    shared_ptr< int > a( new int( 100 ) );
    shared_ptr< int > b;
    b = a;

参照カウンタの制御用にaddref()、reelase()を追加

template < typename T >
class shared_ptr
{
public:
    ...略
    shared_ptr( shared_ptr const& p )
        : ptr( p.ptr )
        , count( p.count )
    {
        addref();
    }

    ~shared_ptr()
    {
        release();
    }

    shared_ptr& operator=( shared_ptr const& p )
    {
        if( this != &p )
        {
            //現在の参照先をreleaseしてからコピー、インクリメント
            release();
            ptr = p.ptr;
            count = p.count;
            addref();
        }
        return *this;
    }

    void addref()
    {
        if( count )
            ++ ( *count );
    }

    void release()
    {
        if( count )
        {
            if( --( *count ) == 0 )
            {
                delete ptr;
                delete count;
            }
        }
    }
    ...略
};

以上で単純なコピーが可能になりました。


ここまでの内容をboostのshared_ptrtと比べてみると、、、全然違いますね^^


次回はshared_countを追加してみましょう。