C++多继承下delete Base2指针报free错误的原因及修复方法
错误原因
- 多继承的对象布局问题:派生类B同时继承Base1、Base2两个基类,编译器会按继承声明顺序在B的内存布局开头依次放置两个基类的子对象:第一个是
Base1子对象,第二个是Base2子对象。- 当你把
new B返回的B*指针赋值给Base1*时,指针指向的地址刚好和B对象的起始地址一致,delete x时传给free的地址和new分配的地址匹配,所以碰巧没有报错。 - 当你把
B*指针赋值给Base2*时,编译器会自动做地址偏移,让指针指向B对象内部的Base2子对象的起始地址,这个地址和new B返回的原始分配地址不一致。
- 当你把
- 核心诱因是基类没有声明虚析构函数:当基类没有虚析构函数时,
delete 基类指针执行的是静态类型匹配,会直接把当前基类指针的地址传给free,而不会先调整回派生类对象的原始起始地址,最终传给free的是偏移后的非法地址,就触发了free(): invalid pointer错误。
注意:哪怕使用Base1指针时程序没有崩溃,这也是未定义行为,只是刚好地址匹配才没有触发错误,不代表代码本身是正确的。
修复方法
只需要给所有用作基类的类添加虚析构函数即可,修改后的基类代码如下:
class Base1 { public: virtual void method1() = 0; virtual ~Base1() = default; // 添加虚析构 }; class Base2 { public: virtual void method2() = 0; virtual ~Base2() = default; // 添加虚析构 };
添加虚析构后,delete 基类指针时会先通过虚表找到派生类的析构函数,自动把指针调整回派生类对象的原始起始地址再释放内存,就不会出现地址不匹配的问题。
内容的提问来源于stack exchange,提问作者Andrea
相关产品推荐
相关产品推荐

