考虑代码:
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
只有默认的析构函数,即我根本没有声明它的析构函数,则不会发生异常。无论析构函数是否为虚函数。在调试和发布版本中都有。
P上。是的,我知道这是未定义的行为。
答案 0 :(得分:8)
在使用delete
创建的指针上调用new[]
是未定义的行为。基本问题是,当你调用new[]
时,它需要分配额外的空间来存储数组中元素的数量,这样当你调用delete []
时,它知道要销毁多少元素。
除了真实对象所需的空间之外,库还将为管理数据分配空间。然后它将执行所有初始化并返回指向第一个元素的指针,该元素与从OS检索到的内存块不对齐。
[header][element1,element2...]
^ ^
| \_ pointer returned by new[]
|
\_ pointer returned by the allocator
另一方面,new
和delete
不存储任何额外信息。
当你调用delete[]
时,它会向后移动指针,读取计数,调用析构函数并使用原始指针解除分配。当您调用delete时,它会调用单个对象的析构函数并将指针传递回分配器。如果指针是通过调用new[]
创建的,则返回给分配器的指针不指定的指针和释放失败。
答案 1 :(得分:3)
因为它是未定义的行为。任何事情都可能发生。