そもそも、スマートポインタの目的とは、new したものを delete し忘れないようにするためのものでした。今実現したいのは、クラス内から this を安全に外部へ渡したいということで、スマートポインタとは目的が違うような気がします。
つまり、shared_ptr を必要としない weak_ptr があればいいのでは?ということで
// ポインタ情報 template <class T> class distributable_data { public : distributable_data( T* ptr_ ) : ptr( ptr_ ), count( 1 ) { } long use_count( void ) const { return this->count; } void reference( void ) { this->count++; } T* get( void ) { return this->ptr; } const T* get( void ) const { return this->ptr; } void clear( void ) { this->ptr = 0; } static bool dereference( distributable_data<T>* data ) { data->count--; if( data->use_count() == 0 ) { delete data; return false; } else { return true; } } private : T* ptr; long count; // ポインタ先ではなく、このクラスの参照数 }; // 配布されるポインタ template <class T> class distributed_ptr { public : distributed_ptr( distributable_data<T>* data_ ) : data( data_ ) { this->data->reference(); } distributed_ptr( const distributed_ptr<T>& org ) : data( org.data ) { this->data->reference(); } ~distributed_ptr( void ) { distributable_data<T>::dereference( this->data ); } bool expire( void ) const { return this->data->get() == 0; } T* operator->( void ) { return this->data->get(); } const T* operator->( void ) const { return this->data->get(); } private : distributable_data<T>* data; }; // 配布可能ポインタ template <class T> class distributable_ptr { public : distributable_ptr( void ) { this->data = new distributable_data<T>( dynamic_cast<T*>(this) ); } virtual ~distributable_ptr( void ) { if( distributable_data<T>::dereference( this->data ) ) { this->data->clear(); } } distributed_ptr<T> lock( void ) { return distributed_ptr<T>( this->data ); } private : distributable_data<T>* data; };こんな感じかな?
※まだ動作検証してません。
で、使うときは、こんな感じに継承して使います。わざわざ継承させるのは、クラスが破棄されたときにコピーされたポインタを無効化するためです。
class Hoge : public distributable_ptr<Hoge> { public : Hoge( void ) : distributable_ptr<Hoge>() { } virtual ~Hoge( void ) { } void Func( void ) { } }; void Foo( void ) { Hoge hoge[ 10 ]; // ポインタ取得 distributed_ptr<Hoge> ptr = hoge[2].lock(); // 使用可能か確認してからアクセス if( !ptr.expire() ) ptr->Func(); }とりあえず、スタック上に配列で確保してみましたが、もちろん new で構築しても問題ありませんし、そのポインタを shared_ptr で管理していても全く問題ないはずです。
distributable_data を構築するのは最初に lock() 関数が呼ばれたときにした方がとか、distributed_ptr のコピー処理とか、スレッドセーフとかも考えるともっといろいろ工夫が必要ですが、とりあえずこんな感じで。しかし、そして、さらに野望が...続く。
0 件のコメント:
コメントを投稿