19

auto_ptr次のように、前方宣言で宣言された型でを使用しようとすると、次のようになります。

class A;
...
std::auto_ptr<A> a;

のデストラクタはA呼び出されません(auto_ptr内部的deleteには基になるポインタであり、不完全な型のデストラクタは呼び出せないためです)。

ただし、同じコードが正常に機能し、のstd::shared_ptr代わりにを使用するとデストラクタが呼び出されstd::auto_ptrます。それはどのように説明できますか?

4

1 に答える 1

35

はい、不完全な型でAshared_ptrを宣言できます。型は、初期化またはリセットするまで完全である必要はありません。

新しいオブジェクトを指すように aを初期化またはリセットするshared_ptrと、オブジェクトを破棄するために使用できる「deleter」が作成されます。たとえば、次のことを考慮してください。

// somewhere where A is incomplete:
std::shared_ptr<class A> p;

// define A
class A { /* ... */ };

p.reset(new A());

を呼び出すと、を使用してインスタンスを作成しているためreset、は完了です。この関数は、 を使用してオブジェクトを破棄するために使用されるデリータを内部的に作成および保存します。はここで完了しているため、正しいことを行います。AnewresetdeleteAdelete

これにより、が宣言されたときにそれが完全であるshared_ptr必要がなくなります。生のポインターを受け取るコンストラクターが呼び出されたとき、または生のポインターで呼び出したときにのみ、それが完了する必要があります。 Ashared_ptr<A>Ashared_ptrreset

これら 2 つのことのいずれかを行うときにifAが完全でないshared_ptr場合は、正しいことを行わず、動作が未定義であることに注意してください (これは のドキュメントで説明されていますboost::shared_ptr。使用shared_ptrしているバージョンshared_ptr(Boost、TR1、C++0x など))。

ただし、常に のベスト プラクティスに従っている限り、特に、を呼び出した結果のポインターを使用して直接shared_ptr初期化およびリセットする場合は、この規則に違反することを心配する必要はありません。shared_ptrnew

この機能は無料ではありません shared_ptr。deleter ファンクターへのポインターを作成して保存する必要があります。通常、これは、強い参照カウントと弱い参照カウントを格納するブロックの一部としてデリータを格納するか、そのブロックの一部としてデリータを指すポインタを持つことによって行われます (独自のデリータを提供できるため)。

auto_ptr(そしてunique_ptrまた) オーバーヘッドがないように設計されています: その操作は、ダム ポインターを使用するのと同じくらい効率的であると想定されています。したがって、auto_ptrこの機能はありません。

于 2011-04-09T17:59:17.973 に答える