51

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 *>は機能するはずなので、コンパイラはそれを理解するのに十分な情報をどこかに格納しています。


助けてくれてありがとう、答えてコメントしてくれたみんな。私の例に示されているように、仮想デストラクタの重要性はすでに知っていました。答えを見た後、私はそれを少し考えました、そして仮想デストラクタの全体の理由がこの正確なシナリオであることに気づきました。したがって、それは機能しなければなりませんでした。ポインタを元に戻すための目に見える手段がないことに私は投げ込まれました。もう少し考えてみると、目に見えない手段があると私は信じました。そして、デストラクタが削除から解放への真のポインタを返していると理論付けました。Microsoft VC ++からコンパイルされたコードを調査すると、〜Baseでこの行を見たときに、私の疑いが確認されました。

mov eax, DWORD PTR _this$[ebp]

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

I've fixed the example to add the virtual destructor to IFoo, it was a simple oversight. Thanks again to everyone who pointed it out.

4

2 に答える 2

64

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

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

于 2008-11-17T05:19:37.790 に答える
3

これは与えられた例とは関係ありませんが、所有しているオブジェクトを削除するときの の動作に本当に関心があると述べたので、's'deleter' のshared_ptr使用に関心があるかもしれません。shared_ptr

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

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

参照またはポインタIFooを介してそのサブクラスであるオブジェクトを削除することを計画しているため、仮想デストラクタを持つように変更できれば最もクリーンです。IFooしかし、IFoo修正できない に行き詰まっている場合、コンテナーで使用したいがshared_ptr<IFoo>、それが を指している場合は、 へのダウンキャストを実行してから削除操作を実行するデリータをBar使用してインスタンスを作成できます。ダウンキャストは悪いフォームと見なされますが、このテクニックはバインドで使用できる可能性があります。shared_ptrBar*

于 2008-11-17T07:19:09.453 に答える