为什么在类对象数组上调用delete而不是delete 会导致堆损坏?

考虑下面的代码:

class A { public: virtual ~A() {} }; class B : public A { public: ~B() {} }; void main () { A * array = new A[100]; delete array; } 

Windows(MSVC 2010)上,它会导致exception,因为delete调用HeapValidate ,然后指出堆已损坏。 这是怎么发生的?

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

注意:如果类A只有默认析构函数,即我没有声明它的析构函数,那么exception就不会发生。 不pipe析构函数是否是虚拟的。 在debugging和发布版本。

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

对于用new[]创建的指针调用delete是未定义的行为。 基本的问题是,当你调用new[]它需要分配额外的空间来存储数组元素的数量,所以当你调用delete []它知道有多少元素要被销毁。

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

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

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

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

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