c++ - 当派生类的析构函数是虚拟的而基类的 dtor 不是时代码崩溃

标签 c++ gcc crash undefined-behavior virtual-destructor

我在 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/

相关文章:

c++ - 当你有一个虚拟析构函数时,基类指针中的 "delete this"会删除派生类对象吗?

c++ - 无法在 Linux 上读取 DDS 图像 header

android - 可搜索微调器使我的应用程序在多任务处理时崩溃

c++ - 为什么 unordered_set 不允许 vector 作为键?

c++ - 我什么时候需要释放内存?

c++ - 可移植浮点变量模板

gcc - 英特尔编译器/LLVM 上的并行位存储/并行位提取?

iphone - StoreKit SKProducts请求崩溃

c++ - 尝试玩 Unreal Engine 4.20 时崩溃?

C++:遍历泛型列表