无虚析构函数时删除虚类实例是否会引发内存泄漏?
C++继承类delete基类指针的内存泄漏与未定义行为问题
先看问题:下面这段代码里,派生类C的成员变量c会不会发生内存泄漏?我自己认为不会,因为它不是动态分配的,类实例应该会被完整销毁,但同事有三种不同观点:
- 属于未定义行为
- 会发生内存泄漏
- 不会发生内存泄漏
代码如下:
#include <iostream> using namespace std; class A { public: void printA() { cout << "A" << endl;} virtual void printB() { cout << "B" << endl;} int a; }; class C : public A { public : void printA() { cout << "C" << endl;} void printB() { cout << "D" << endl;} int c; }; int main() { A* bla = new C(); bla->printA(); bla->printB(); delete bla; return 0; }
核心结论
首先明确——这段代码的delete bla;属于未定义行为,这是C++标准明确规定的:当用基类指针删除派生类对象时,如果基类没有声明虚析构函数,整个操作的行为是未定义的。
对三个观点的分析
- 属于未定义行为:这个观点完全正确。未定义行为意味着程序的运行结果没有任何保证,编译器可以自由处理,可能看起来正常,可能崩溃,也可能出现内存泄漏,一切都不可控。
- 会发生内存泄漏:这个说法不准确。成员变量
c是派生类对象的一部分,和整个对象一起在堆上分配。有些编译器可能会在delete时释放整个对象的内存(即使没调用派生类析构函数),此时c占用的内存会被回收;但如果派生类有动态分配的成员(比如new出来的指针),那肯定会泄漏,但这里c是普通int,所以内存是否泄漏完全取决于编译器的实现,不能一概而论。 - 不会发生内存泄漏:同样不能确定。因为未定义行为的存在,你无法保证编译器一定会释放整个对象的内存,也无法保证析构过程没有其他问题,所以不能断言“一定不会泄漏”。
正确的解决方式
给基类A添加一个虚析构函数,这样当用基类指针delete派生类对象时,会正确调用派生类的析构函数,整个对象的内存会被完整释放,行为完全确定:
class A { public: void printA() { cout << "A" << endl;} virtual void printB() { cout << "B" << endl;} virtual ~A() {} // 添加虚析构函数 int a; };
内容的提问来源于stack exchange,提问作者OopsUser
相关产品推荐
相关产品推荐

