web-dev-qa-db-ja.com

削除は基本クラスへのポインタで機能しますか?

Newが返したのと同じポインタを削除して渡す必要がありますか、それともクラスの基本型の1つへのポインタを渡すことができますか?例えば:

class Base
{
public:
    virtual ~Base();
    ...
};

class IFoo
{
public:
    virtual ~IFoo() {}
    virtual void DoSomething() = 0;
};

class Bar : public Base, public IFoo
{
public:
    virtual ~Bar();
    void DoSomething();
    ...
};

Bar * pBar = new Bar;
IFoo * pFoo = pBar;
delete pFoo;

もちろん、これは大幅に簡略化されています。私が本当にやりたいことは、boost :: shared_ptrでいっぱいのコンテナーを作成し、それをいくつかのコードに渡して、完了時にコンテナーから削除することです。このコードは、BarまたはBaseの実装について何も認識せず、shared_ptrデストラクタの暗黙の削除演算子に依存して正しいことを行います。

これはおそらく機能しますか?ポインターは同じアドレスを持たないので、私の直感は「いいえ」です。一方、dynamic_cast <Bar *>は機能するはずなので、コンパイラーがどこかにそれを理解するのに十分な情報を格納しています。


全体の理由
mov eax, DWORD PTR _this$[ebp]

アセンブラーをトレースすると、これが削除関数に渡されるポインターであることがわかりました。謎解きました。

仮想デストラクタをIFooに追加する例を修正しましたが、これは単純な見落としでした。指摘してくれた皆さん、ありがとうございました。

45
Mark Ransom

はい、動作しますif if only only基本クラスデストラクタが仮想であり、Base基本クラスに対して実行したものの、IFoo基本クラスに対して実行したものではありません。基本クラスデストラクタが仮想の場合、基本クラスポインタでoperator deleteを呼び出すと、動的ディスパッチを使用して、仮想関数テーブルで派生クラスデストラクタを検索することにより、オブジェクトを削除する方法がわかります。

多重継承の場合、削除するベースクラスに仮想デストラクタがある場合にのみ機能します。他の基本クラスが仮想デストラクタを持たなくても問題ありませんが、他の基本クラスポインターを介して派生オブジェクトを削除しない場合のみです。

57
Adam Rosenfield

これは特定の例とは関係ありませんが、所有オブジェクトを削除するときのshared_ptrの動作に本当に関心があると述べたので、shared_ptrの「削除機能」の使用に関心があるかもしれません。

shared_ptrが所有するオブジェクトを削除するときに特別な処理が必要な場合は、特定のshared_ptr<>に「deleter」を指定できます。削除者はタイプの一部ではなく、shared_ptr<>インスタンスの属性であるため、shared_ptr<>オブジェクトのコンテナには、異なる削除者を持つオブジェクトが含まれる可能性があります。 Boostのドキュメントでshared_ptr<>の削除について次のように言っています。

カスタムデアロケータを使用すると、ファクトリ関数がshared_ptrを返し、ユーザーをメモリ割り当て戦略から隔離できます。デアロケータはタイプの一部ではないため、割り当て戦略を変更しても、ソースまたはバイナリの互換性は損なわれず、クライアントの再コンパイルは必要ありません。たとえば、「no-op」デアロケータは、静的に割り当てられたオブジェクトにshared_ptrを返すときに役立ちます。他のバリエーションでは、shared_ptrを別のスマートポインタのラッパーとして使用できるため、相互運用性が向上します。

IFoo参照またはポインタを介してそのサブクラスであるオブジェクトを削除する予定なので、IFooを仮想デストラクタに変更できると最もクリーンです。ただし、修正できないIFooでスタックしている場合、コンテナでshared_ptr<IFoo>を使用したいが、Barを指している場合は、 shared_ptrへのダウンキャストを実行する削除機能を備えたBar*インスタンスは、その後、削除操作を実行します。ダウンキャストは不適切な形式と見なされますが、この手法はバインドで使用できるものかもしれません。

3
Michael Burr