そもそも、スマートポインタの目的とは、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 件のコメント:
コメントを投稿