我在 gcc 4.4.5 上尝试了以下代码。
如果成员“data”不存在,代码执行正常,但在它存在的情况下,它会崩溃。当派生类的 dtor 不是虚拟时,它也不会崩溃。
我知道在这两种情况下行为都是未定义的,如 C++03 (5.3.5/3) 中所列,但仍然有人可以向我提供一些解释,为什么它在后一种情况下崩溃了?
是的,我知道 UB 意味着任何事情都可能发生,但仍然我想知道特定于实现的细节。
#include<iostream>
using std::cout;
struct base{
int data;
base(){
cout << "ctor of base\n";
}
~base(){
cout << "dtor of base\n";
}
};
struct derived : base{
derived(){
cout << "ctor of derived\n";
}
virtual ~derived(){
cout << "dtor of derived\n";
}
};
int main(){
base *p = new derived;
delete p;
}
最佳答案
假设在我的系统(gcc 4.6.0,linux x86_64)上发生的事情与在你的系统上发生的事情相同(它也因 data
而崩溃并且在没有数据的情况下运行),实现细节是 p
不指向为derived
类型的对象分配的内存块的开头。
正如 valgrind
告诉我的那样,
Address 0x595c048 is 8 bytes inside a block of size 16 alloc'd
如果打印指针的值,您可以自己看到这一点:
derived * d = new derived;
std::cout << d << '\n';
base *p = d;
std::cout << p << '\n';
原因是 gcc 中的对象布局是 {vtable, base, derived}
当 base 为空时,{vtable, base, derived} 和 {base} 的大小恰好相同,因为分配一个空类的对象占用非零字节数,这两种情况恰好相等。
当 derived 没有虚函数时,vtable 不存在,地址再次相同,删除成功。
关于c++ - 当派生类的析构函数是虚拟的而基类的 dtor 不是时代码崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6155285/