まず第一に、このままではコードが機能しないということです。のデストラクタはbase
少なくともprotected
(または派生クラスがベースのフレンドである) 必要があります。private
デストラクタとは、コンパイラが派生クラスのデストラクタを記述することを許可しないことを意味します。protected
ここで、デストラクタがあると仮定します... (拡張するクラスを設計する場合は、パブリック仮想デストラクタまたは保護された非仮想デストラクタのいずれかを提供してください!)
すべては の実装に依存し、SmartPointer
特にstd::shared_ptr
(またはブースト対応のboost::shared_ptr
) はその状況をきれいに管理できます。このソリューションは、破壊目的で型のある種の部分的な型消去を実行します。基本的に、スマート ポインターには、ポインターに割り当てることができる任意のポインターを受け入れるテンプレート化されたコンストラクターがありますが、テンプレート化されているbase
ため、具体的な型を認識しています。その時点でdeleter
、適切なデストラクタを呼び出す合成関数が格納されます。
簡単にするために、次を使用しstd::function
ます。
template <typename T>
void delete_deleter( void * p ) {
delete static_cast<T*>(p);
}
template <typename T>
class shared_pointer {
T * ptr;
std::function<void(void*)> deleter;
public:
template <typename U>
shared_pointer( U* p, std::function<void()> d = delete_deleter<U> )
: ptr(p), deleter(d)
{}
~shared_pointer() {
deleter( ptr ); // call the stored destructor
}
};
コードは展示専用です。本番用に微調整する必要があります(function
参照カウントを保存する場所...)が、アイデアを与えるには十分です:オブジェクトの正確なタイプが知られている場合 (スマート ポインターを作成するとき)、必要なデストラクタの正確なバージョンを呼び出すラッパーを作成し (タイプ消去の一部を提供します)、それをそのままにしてdelete
、オブジェクトが必要なときに代わりにそれを呼び出します。delete
オペレーター。
これは、代わりに特別なメソッドを呼び出す必要がある他のリソースを管理するためにも使用できますdelete
。
// exhibition only!
shared_pointer<Foo> p( Factory.create(), &Factory::release );
繰り返しますが、このプロダクションの準備を整える前に、かなり多くの作業が必要です。
消去を簡素化するために使用される依存関係std::function
は、問題から排除できます。単純なケース (スマート ポインターで割り当てられたメモリnew
と解放されたメモリのみdelete
がサポートされます) では、deleter
基本クラスに単一の virtual を提供し、既存のクラスを現在の実装でそのオーバーライドからテンプレート化された派生クラスにoperator()(void*)
リファクタリングします。一般的なケース (任意のタイプのリソースを保持する) を使用する必要がある場合は、努力する価値はありません。単にまたはを使用してください。delete_deleter
deleter
operator()(void*)
std::function
boost::function