1

考虑代码:

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

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

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

在 Windows (MSVC 2010) 上,它会导致异常,因为delete调用HeapValidate,这表明堆已损坏。这是如何以及为什么会发生的?

我确实意识到delete[]应该在这里调用,当然这样就没有问题了。但是为什么会delete导致堆损坏呢?据我所知,它应该为第一个对象(array[0]*array)调用析构函数,然后释放整个块。现实中会发生什么?

注意:如果类A只有默认析构函数,即我根本没有声明它的析构函数,则不会发生异常。不管析构函数是否是虚拟的。在调试和发布版本中。

PS是的,我知道这是未定义的行为。

4

2 回答 2

9

调用delete使用创建的指针是未定义的行为new[]。基本问题是调用new[]时需要分配额外的空间来存储数组中元素的数量,以便调用delete []时知道要销毁多少元素。

除了真实对象所需的空间外,库还将为管理数据分配空间。然后它将执行所有初始化并返回指向第一个元素的指针,该元素与从操作系统检索的内存块不对齐。

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

另一方面,new不要delete存储任何额外的信息。

当您调用delete[]它时,将指针移回,读取计数,调用析构函数并使用原始指针解除分配。当您调用 delete 时,它​​会调用单个对象的析构函数并将指针传递回分配器。如果指针是通过调用创建的new[],则返回给分配器指针与分配的指针不同,并且释放失败。

于 2013-02-25T18:47:41.137 回答
3

因为它是未定义的行为。任何事情都有可能发生。

于 2013-02-25T18:38:26.857 回答