これには std::auto_ptr を実際に使用しないでください。std::auto_ptr を宣言した時点ではデストラクタが表示されないため、適切に呼び出されない可能性があります。これは、pImpl クラスを前方宣言し、別のファイルのコンストラクター内にインスタンスを作成していることを前提としています。
boost::scoped_ptrを使用する場合(ここでは shared_ptr は必要ありません。pimpl を他のオブジェクトと共有することはありません。これはscoped_ptrが noncopyable であることによって強制されます)、呼び出した時点で表示される pimpl デストラクタのみが必要です。 scoped_ptr コンストラクター。
例えば
// in MyClass.h
class Pimpl;
class MyClass
{
private:
std::auto_ptr<Pimpl> pimpl;
public:
MyClass();
};
// Body of these functions in MyClass.cpp
ここで、コンパイラは MyClass のデストラクタを生成します。auto_ptr のデストラクタを呼び出す必要があります。auto_ptr デストラクタがインスタンス化される時点で、Pimpl は不完全な型です。そのため、Pimpl オブジェクトを削除するときに auto_ptr デストラクタに入ると、Pimpl デストラクタを呼び出す方法がわかりません。
boost::scoped_ptr (および shared_ptr) にはこの問題はありません。これは、scoped_ptr (または reset メソッド) のコンストラクターを呼び出すと、delete を呼び出す代わりに使用される関数ポインターと同等のものも作成されるためです。ここで重要な点は、Pimpl が不完全型でない場合に解放関数をインスタンス化することです。補足として、shared_ptr を使用すると、カスタムの割り当て解除関数を指定できるため、GDI ハンドルなど、必要なものに使用できますが、ここでのニーズには過剰です。
本当に std::auto_ptr を使用したい場合は、Pimpl が完全に定義されているときに MyClass.cpp で MyClass デストラクタを定義していることを確認して、特別な注意を払う必要があります。
// in MyClass.h
class Pimpl;
class MyClass
{
private:
std::auto_ptr<Pimpl> pimpl;
public:
MyClass();
~MyClass();
};
と
// in MyClass.cpp
#include "Pimpl.h"
MyClass::MyClass() : pimpl(new Pimpl(blah))
{
}
MyClass::~MyClass()
{
// this needs to be here, even when empty
}
コンパイラは、すべての MyClass メンバーを事実上空のデストラクタ内で破壊するコードを生成します。そのため、auto_ptr デストラクタがインスタンス化された時点で、Pimpl はもはや不完全ではなく、コンパイラはデストラクタを呼び出す方法を認識しています。
個人的には、すべてが正しいことを確認する手間をかける価値はないと思います。また、後で誰かがやってきて、冗長に見えるデストラクタを削除してコードを整理するリスクもあります。したがって、この種のことについては、boost::scoped_ptr を使用する方が全体的に安全です。