smart_this(5)
なんで null になっているかというと、_this へスマートポインタをセットした後に、コンストラクタを呼び出しているからだ。
せっかくセットしたのに、コンストラクタで初期化されて、再び null になってしまう。
コンストラクタで初期化しないクラスを作ればいいかもしれないが、出来る限りそっち側は触りたくない。
ではどうするかというと、スマートポインタへのポインタを持つようにする。
そしてコンストラクタを呼び出す前に _pThis を new してやればいい。
template< class T > class smart_this{ static smart_ptr< T > create(){ smart_ptr< T > s = smart_ptr< T >( (T*)malloc( sizeof( T ) ) ); SmartThisPtrGetter()( *s ) = ::new smart_ptr< T >(); *SmartThisPtrGetter()( *s ) = s; s.dec_ref(); ::new( (void*)s.get() ) T(); return s; } protected: smart_this(){} ~smart_this() { ::delete _pThis; } private: smart_ptr< T >* _pThis; };
これで大丈夫なはずだ。
SmartPtrInitializer も消えるので、これでスマートポインタ側のソースを改変することなく、全ての処理を完了できる。
そして、最後の問題は継承。
class Base : public smart_this< Base >{}; class Inherit : public Base{};
こんなクラスがあったとして、
smart_ptr< Base > obj = smart_this< Inherit >::create();
こうすると、create() によって生成されるのは smart_ptr< Inherit > であり、smart_ptr< Base > ではない。
キャストが出来なかった場合、コンパイルエラーだ。
キャストが出来る場合は、これで正しい。
今使っているスマートポインタにはキャストの機能が付いているとする。
で、キャストが出来るのであれば、スマートポインタは void でいいのではないだろうか。と思うわけだ。
そして、生成するときだけ型を指定してやれば、そのサイズのオブジェクトを生成すればいいのだ。
で、自分が作った完成版はこんなの。
class SmartThisPtrGetter; class smart_this{ public: // 引数無し template< class T > static smart_ptr< T > create( T* ){ smart_ptr< T > s = innerCreate( (T*)0 ); ::new( (void*)s.get() ) T(); return s; } // 引数1個 template< class T , class V1 > static smart_ptr< T > create( T* , V1& v1 ){ smart_ptr< T > s = innerCreate( (T*)0 ); ::new( (void*)s.get() ) T( v1 ); return s; } // 以下略 ... public: smart_ptr< void > getThis(){ return *_pThis; } smart_this(){} ~smart_this() { ::delete _pThis; } private: template< class T > static smart_ptr< T > innerCreate( T* ){ smart_ptr< T > s = smart_ptr< T >( (T*)::operator new( sizeof( T ) ) ); SmartThisPtrGetter()( *s ) = ::new smart_ptr< void >(); *SmartThisPtrGetter()( *s ) = s; s->dec_ref(); return s; } void* operator new( size_t size ){} void operator delete( void* ptr ){} smart_ptr< void >* _pThis; friend class SmartThisPtrGetter; }; class SmartThisPtrGetter{ private: smart_ptr< void >*& operator()( smart_this& s ) { return s._pThis; } friend class smart_this; };
完成!ヽ(´ー`)ノ
クラスの定義時にテンプレートの型を指定する必要が無くなった。
しかし、生成が少し分かりづらくなっている。
class Base : public smart_this{ // 型は指定しなくていい }; class Inherit : public Base{};
// こっちで型を指定する
smart_ptr< Base > obj = smart_this::create( (Inherit*)0 );
第一引数に生成したい型を指定している。
これは create< Inherit >() という形式で使用出来ないからだ。
これだと分かりづらいので、生成するためのクラスを用意しておくといいかもしれない。
template< class T > class smart_this_creator{ public: // 引数無し static smart_ptr< T > create() { return smart_this::create( (T*)0 ); } // 引数1個 template< class V1 > static smart_ptr< T > create( V1& v1 ) { return smart_this::create( (T*)0 , v1 ); } // 以下略 ... };
smart_ptr< Base > obj = smart_this_creator< Inherit >::create();
今度こそ完成!
少なくとも自分の中では使いやすいテンプレートになったので満足満足(*´ω`)