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

标签 c++ windows memory-management destructor

考虑代码:

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)调用析构函数,然后释放整个 block 。现实中会发生什么?

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

P. S. 是的,我知道这是未定义的行为。

最佳答案

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

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

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

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

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

关于c++ - 为什么在类对象数组上调用 delete 而不是 delete[] 会导致堆损坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15073970/

相关文章:

c++ - 将滚动条与 QGridLayout 一起使用

android - 为 Android 编译英特尔 TBB - ARMv7 ARMv8 MIPS

c++ - 错误忽略某些文件

objective-c - 更具体、通用的 Objective-C 内存管理

php - gc_collect_cycles 函数有什么用?

c++ - 字符串到 vector 的转换抛出 std::bad_alloc

java - 获取没有 '~' 字符的路径

windows - 是否有(免费的)Windows 测试/虚拟打印设备?

windows - 在外部程序执行时捕获它的 STDOUT 和 STDERR (Ruby)

c++ - 删除对象会将其引用设置为 NULL 吗?