BREW Smart Pointer(5)
あとはスマートポインタ同士のキャストさえ出来れば完成だ。
スマートポインタ同士でキャストする方法。それは非常に簡単だ。
// 参照カウントを行うためのクラス class BrewRefObject{ public: // コンストラクタ BrewRefObject() : _obj( null ) , _ref( null ){ } // デストラクタ ~BrewRefObject(){ Release(); } // コピーコンストラクタ BrewRefObject( const BrewRefObject& s ) : _obj( null ) , _ref( null ){ Set( s ); } // null に対するコンストラクタ BrewRefObject( long ) : _obj( null ) , _ref( null ){ } // 代入演算子 BrewRefObject& operator=( const BrewRefObject& s ){ Set( s ); return (*this); } // null に対する代入演算子 BrewRefObject& operator=( long ){ Release(); return (*this); } // getter void* get() const{ return _obj; } // public にするのはあまり良くないんだけど……。 BrewRefCountDeleterBase* getRefCountDeleter() const{ return _ref; } protected: // オブジェクトをセットします void Set( const BrewRefObject& s ){ if( (void*)this != (void*)&s ){ Release(); _obj = s.get(); _ref = s.getRefCountDeleter(); if( _ref != null ){ _ref->inc(); } } } // 自身の参照数を減らします void Release(){ if( _ref != null && _ref->dec() == 0 ){ _ref->Delete( _obj ); delete _ref; } _obj = null; _ref = null; } protected: void* _obj; //!< 実体へのポインタ BrewRefCountDeleterBase* _ref; //!< 参照カウンタ }; // スマートポインタクラス template< class T > class BrewSmartPtr : public BrewRefObject{ public: // コンストラクタ BrewSmartPtr(){ } // コピーコンストラクタ BrewSmartPtr( const BrewRefObject& s ) : BrewRefObject( s ){ } // ポインタをセット。Deleter は BrewRefCountDeleter template< class U > BrewSmartPtr( U* p ){ Set( p ); } // Deleter 付きでポインタをセット template< class U , class Deleter > BrewSmartPtr( U* p , Deleter deleter ){ Set( p , deleter ); } // 代入演算子 __inline BrewSmartPtr& operator=( const BrewRefObject& s ){ return *(BrewSmartPtr*)&BrewRefObject::operator=( s ); } // null に対する代入演算子 __inline BrewSmartPtr& operator=( long ){ return *(BrewSmartPtr*)&BrewRefObject::operator=( null ); } // ポインタをセット。Deleter は BrewRefCountDeleter template< class U > void Set( U* p ){ Set( p , BrewRefCountDeleter< U >() ); } // Deleter 付きでポインタをセット template< class U , class Deleter > void Set( U* p , Deleter ){ Release(); if( p != null ){ _obj = static_cast< T* >( p ); _ref = new Deleter(); } } __inline T* operator->() const{ return get(); } __inline T& operator*() const{ return *get(); } __inline T* get() const{ return (T*)BrewRefObject::get(); } };
そう、継承をすればいいのだ。そして、その上位クラスとのコピーコンストラクタを用意しておく。
すると、他のスマートポインタクラスを代入する際に、一度上位クラスに変換されるので、コピーが出来るようになる。
例えば、
BrewSmartPtr< int > intPtr( new int ); BrewSmartPtr< byte > bytePtr; bytePtr = intPtr;
こういう処理を行った場合、最後の代入では、intPtr が BrewRefObject 型へと変換され、BrewSmartPtr< byte >::operator=( const BrewRefObject ) が実行される。
これによって、全てのスマートポインタ間で代入やコピーが行えるようになるのだ。
また、短い関数を出来る限りインライン展開することによって、無駄な関数呼び出しを減らしている。
アロー演算子や間接参照演算子の呼び出しコストは限りなく少ないだろう。
そして、BrewRefObject は全てのスマートポインタの基底クラスなのだ。つまり、void* と同等の役割を果たす。
全ての型の違うオブジェクトをこれで管理し、必要に応じて元の型に戻して返すという手法も可能だということだ。
惜しむらくは元の型の情報を BrewRefObject クラスが持っていないということだろうか。
こうしてスマートポインタクラスは組み上がった。
彼はこのスマートポインタを使い、恐ろしく効率を上げた。バグも減った。表現出来るパターンが増えた。まあ、その分仕事も増えたのだが。
だが彼は驕ったりなどしない。彼は、自分がいかに狭い世界に住んでいるか知っている。いわば彼は井戸から這い出て、山へ登る準備を整え、エベレストへ脚を掛けようとしているところだ。
そう、彼のスーパープログラマへの道はここから始まる...。