You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无虚析构函数时删除虚类实例是否会引发内存泄漏?

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++标准明确规定的:当用基类指针删除派生类对象时,如果基类没有声明虚析构函数,整个操作的行为是未定义的。

对三个观点的分析

  1. 属于未定义行为:这个观点完全正确。未定义行为意味着程序的运行结果没有任何保证,编译器可以自由处理,可能看起来正常,可能崩溃,也可能出现内存泄漏,一切都不可控。
  2. 会发生内存泄漏:这个说法不准确。成员变量c是派生类对象的一部分,和整个对象一起在堆上分配。有些编译器可能会在delete时释放整个对象的内存(即使没调用派生类析构函数),此时c占用的内存会被回收;但如果派生类有动态分配的成员(比如new出来的指针),那肯定会泄漏,但这里c是普通int,所以内存是否泄漏完全取决于编译器的实现,不能一概而论。
  3. 不会发生内存泄漏:同样不能确定。因为未定义行为的存在,你无法保证编译器一定会释放整个对象的内存,也无法保证析构过程没有其他问题,所以不能断言“一定不会泄漏”。

正确的解决方式

给基类A添加一个虚析构函数,这样当用基类指针delete派生类对象时,会正确调用派生类的析构函数,整个对象的内存会被完整释放,行为完全确定:

class A 
{
public:
    void printA() { cout << "A" << endl;}
    virtual void printB() { cout << "B" << endl;}
    virtual ~A() {} // 添加虚析构函数
    int a;
};

内容的提问来源于stack exchange,提问作者OopsUser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 18:45:33