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

问题描述

| 我在gcc 4.4.5上尝试了以下代码。 如果不存在成员“数据”,则代码可以正常执行,但是如果存在,则将崩溃。当派生类的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
,并且在没有
data
的情况下运行),实现细节是
p
不指向内存块的开头分配给类型为“ 3”的对象。 就像ѭ4告诉我的那样
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}的大小恰好相同,因为分配空类的对象占用的字节数为非零,这两种情况都相等。 当派生没有虚拟功能时,vtable不存在,地址再次相同,删除成功。     ,        两种类型的大小不匹配,示例中的布局也应不同。 您正在将吊舱类型与带有vtable的类型进行比较(布局和偏移量是由实现定义的)。调用析构函数时,假定其隐式地址的布局为
base
,但实际上为
derived
。执行的操作等效于从无效地址进行写入/读取。     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...