1

コードを考えてみましょう:

class A {
public:
    virtual ~A() {}
};

class B : public A {
public:
    ~B() {}
};

void main ()
{
    A * array = new A[100];
    delete array;
}

deleteWindows(MSVC 2010)では、呼び出しが原因で例外が発生HeapValidateし、ヒープが破損していることを示します。これはどのように、そしてなぜ起こるのですか?

確かにdelete[]ここで呼ばれるべきだと思いますが、もちろん問題ありません。しかし、なぜdeleteヒープの破損を引き起こすのでしょうか。私の知る限り、最初のオブジェクト(array[0]または*array)のデストラクタを呼び出してから、ブロック全体を解放する必要があります。実際にはどうなりますか?

注:クラスAにデフォルトのデストラクタしかない場合、つまりデストラクタをまったく宣言しない場合、例外は発生しません。デストラクタが仮想であるかどうかに関係なく。デバッグビルドとリリースビルドの両方。

PSはい、これは未定義の動作であることを私は知っています。

4

2 に答える 2

9

deleteで作成されたポインタを呼び出すことは未定義の動作new[]です。基本的な問題は、呼び出すときnew[]に配列内の要素の数を格納するために余分なスペースを割り当てる必要があるため、呼び出すときdelete []に破棄する要素の数がわかることです。

ライブラリは、実際のオブジェクトに必要なスペースに加えて、管理データ用のスペースを割り当てます。次に、すべての初期化を実行し、OSから取得したメモリのブロックと整列していない最初の要素へのポインタを返します。

[header][element1,element2...]
^       ^
|       \_ pointer returned by new[]
|
\_ pointer returned by the allocator

一方、追加情報は保存newdeleteないでください。

呼び出すdelete[]と、ポインタが戻り、カウントが読み取られ、デストラクタが呼び出され、元のポインタを使用して割り当てが解除されます。deleteを呼び出すと、単一オブジェクトのデストラクタが呼び出され、ポインタがアロケータに返されます。ポインタがへの呼び出しによって作成された場合、new[]アロケータに返されるポインタは割り当てられたものと同じポインタではなく、割り当て解除は失敗します。

于 2013-02-25T18:47:41.137 に答える
3

未定義の動作だからです。何でも起れる。

于 2013-02-25T18:38:26.857 に答える