smart_this(4)

次は4番。private な _this へアクセスするための権限が無いという問題。
これは、_this への参照を返すようなクラスを作成し、そこから取得するようにすればいい。

template< class T > class SmartThisPtrGetter;

template< class T >
class smart_this{
    ...
    
    friend class SmartThisPtrGetter< T >;
};

template< class T >
SmartThisPtrGetter{
private:
    smart_ptr< T >& operator()( smart_this< T >& s ){
        return s._this;
    }
    
    friend class smart_this< T >;
};

こうすれば、

s._this
SmartThisPtrGetter()( s )

この2行は同じ意味になる。



そして2番。_this に代入する時点で、_this が初期化されていないという問題。
これは、4番と同じ方法で、_this を初期化してやればいい。

class SmartPtrInitializer;

template< class T >
class smart_ptr{
    ...
    
    friend class SmartPtrInitializer;
};

class SmartPtrInitializer{
public:
    template< class T >
    void operator()( smart_ptr< T >& s ){
        // 参照カウンタオブジェクトへのポインタ
        s._refObj = null;
        // T型オブジェクトへのポインタ
        s._obj = null;
    }
};

コンストラクタで行う処理を、SmartPtrInitializer が代行する。
これで、_this のコンストラクタを呼び出したのと同じ状態になる。




で、今までの1〜4を組み合わせると、こうなる。

template< class T >
class smart_this{
public:
    static smart_ptr< T > create(){
        smart_ptr< T > s = smart_ptr< T >( (T*)malloc( sizeof( T ) ) );
        SmartPtrInitializer()( SmartThisPtrGetter()( *s ) );
        SmartThisPtrGetter()( *s ) = s;
        s.dec_ref();
        ::new( (void*)s.get() ) T();
        return s;
    }
protected:
    smart_this(){}
private:
    smart_ptr< T >  _this;
};

メモリを確保し、それをスマートポインタにセットして、_this を初期化して、_this に s をセットして、参照数を減らして、コンストラクタを呼んでる。
これでいけるはずだ。

class Hoge : public smart_this< Hoge >{
};
smart_ptr< Hoge > hoge = smart_this< Hoge >::create();

一応コンパイルは通るはずだ。


しかし、hoge にセットされた時点で、_this の中身が null になっている。なぜだろう?


続く。