6

次のコードでは、ptrが削除されると、デストラクタ for が呼び出されますが、デストラクタ forBaseは呼び出されませんDerived(デストラクタBaseが仮想ではないため)。

class Base
{
  int b;
};

class Derived : public Base
{
  int d;
};

int main(void)
{
    Base * ptr = new Derived();
    delete ptr;
    return 0;
}

Valgrind は、プログラムにメモリ リークが含まれていないと報告しています。私の質問は - の(デフォルトの)デストラクタがDerived呼び出されない場合、メモリのd割り当て解除または再利用はいつ、どのように行われるのでしょうか?

4

3 に答える 3

8

delete基本クラスのデストラクタがそうでない場合、派生クラス オブジェクトを指す基本クラス ポインタで呼び出すのは、未定義の動作virtualです。

未定義の動作とは、何でも起こり得ることを意味します。メモリ リークが発生するかどうかは、プログラムが任意の動作を示す可能性があり、表示される動作に依存できないという事実に関係ありません。

コードが有効であるためには、Base クラスのデストラクタがvirtual.


C++11 標準 5.3.5 削除:
パラ 3:

最初の選択肢 (オブジェクトの削除) では、削除するオブジェクトの静的型がその動的型と異なる場合、静的型は削除するオブジェクトの動的型の基本クラスであり、静的型は仮想デストラクタまたは動作が undefinedです。2 番目の選択肢 (配列の削除) では、削除するオブジェクトの動的な型がその静的な型と異なる場合、動作は未定義です。

于 2013-02-22T11:34:32.460 に答える
2

間違ったデストラクタを呼び出すことは、未定義の動作だと思います。仮想デストラクタが必要です。

ただし、割り当ては Derived クラスの 1 つのブロックで行われるため、derived クラスの内部は単に割り当てのサイズを追跡し、オブジェクトが占有する 4 バイトではなく 8 バイトを解放するため、「機能」します。そのベースが使用します。

仮想デストラクタ自体は、this指すメモリを解放する責任を負わないことに注意してください。これはdelete、デストラクタが呼び出された後に発生します。

于 2013-02-22T11:35:24.703 に答える
1

他の偉大な人が述べたように、標準では未定義の動作であると述べていますが、通常、競合やユーザーを気にするコンパイラの間では、これはシステム アロケータの実装次第であり、プラットフォームごとに異なる可能性があります。Derivedデストラクタ自体は、フィールドを含むオブジェクトのメモリを解放しません。

を呼び出すとnew Derived、 のグローバル実装operator newが呼び出され、割り当てるバイト数を受け取ります。それはsizeof(Derived)あなたの場合になります。

実際にメモリを解放すると (global operator delete)、アロケータは、解放されるオブジェクトのアドレスから解放するバイト数を認識します。そのため、 と の両方bで使用されているメモリdが再利用されます

于 2013-02-22T11:27:54.633 に答える