BREW Smart Pointer(4)

やはりスマートポインタクラスはテンプレートである必要がある。


なぜなら、型に依存したポインタを返すようにしたいからだ。

T* get() const{ return static_cast< T* >( _obj ); }

こうするためには、やはりスマートポインタクラスはテンプレートである必要がある。
ということは、テンプレートの肥大化を防ぐには、スマートポインタクラスの外部にその実装を置く必要がある。
ヘルパクラスを作って、そこに実装すればいいのだろうか。

// スマートポインタの代替クラス
class BrewSmartPtrProxy{
public:
    void*                       obj;
    BrewRefCountDeleterBase*    ref;
};

class BrewSmartPtrHelper{
public:
    // スマートポインタのセットを行うためのヘルパ関数
    static void Set( BrewSmartPtrProxy& dst , const BrewSmartPtrProxy& src ){
        if( (void*)&dst != (void*)&src ){
            Release( dst );
            dst.obj = src.obj;
            dst.ref = src.ref;
            if( dst.ref != null ){
                dst.ref->inc();
            }
        }
    }
    
    // スマートポインタの解放を行うためのヘルパ関数
    static void Release( BrewSmartPtrProxy& dst ){
        if( dst.ref != null && dst.ref->dec() == 0 ){
            dst.ref->Delete( dst.obj );
            delete dst.ref;
        }
        dst.obj = null;
        dst.ref = null;
    }
};

template< class T >
class BrewSmartPtr{
public:
    ....
    
    // スマートポインタの代入
    void Set( const BrewSmartPtr& s ){
        BrewSmartPtrHelper::Set( *(BrewSmartPtrProxy*)this , *(BrewSmartPtrProxy* const)&s );
    }
    
    // 解放
    void Release(){
        BrewSmartPtrHelper::Release( *(BrewSmartPtrProxy*)this );
    }
    
    // getter, アロー演算子、間接参照演算子
    T* get() const{ return static_cast< T* >( _obj ); }
    T* operator->() const{ return get(); }
    T& operator*() const{ return *get(); }
    
private:
    ....
};

なるほど、これなら型に依存したポインタを返しつつ、バイナリサイズも増加しない。


これで大丈夫だろうか。もう一度コードを読み返したジョン。ああ、ダメだ。見ただけで分かる。これではダメだ。
スマートポインタ同士のキャストが出来ない。
Set() をメンバ関数テンプレートにすれば不可能ではないだろう。そう、不可能ではない。コードサイズの増加という、今回のスマートポインタの改良に至った目的を根底から潰してしまうという事実と引き替えに、だが。
これなら前に書いた非テンプレート版のスマートポインタの方が、コードサイズを増加させないという本来の目的を達成している分、遙かに行儀が良かった。
だがこのスマートポインタも無駄ではない。そう、スマートポインタをテンプレートで記述し、Set(), Release() を外部に出すことは出来ているのだ。
ただ、Set() が T 型に依存してしまっているだけなのだ。


そう、ゴールはもう目の前にある。(つづく)