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

Vio*_*ffe 1 c++ windows destructor memory-management

考虑一下代码:

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

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

void main ()
{
    A * array = new A[100];
    delete array;
}
Run Code Online (Sandbox Code Playgroud)

在Windows(MSVC 2010)上,它会导致异常,因为delete调用HeapValidate会指示堆已损坏.这是怎么发生的?

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

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

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

Dav*_*eas 8

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

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

[header][element1,element2...]
^       ^
|       \_ pointer returned by new[]
|
\_ pointer returned by the allocator
Run Code Online (Sandbox Code Playgroud)

另一方面,new并且delete不存储任何额外信息.

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

  • 请注意,第一句话是关于此事的所有标准.以下是典型实现可能做的事情; 该标准并未强制要求,细节可能因平台或工具链而异,也可能因工具链而异.+1 (6认同)
  • 一些编译器[优化该案例](http://blogs.msdn.com/b/oldnewthing/archive/2004/02/03/66660.aspx). (2认同)