C++中析构函数不设为virtual导致内存泄漏示例

一、问题示例

cpp 复制代码
#include <iostream>
using namespace std;

class Base {
public:
    Base() { cout << "Base constructor\n"; }
    ~Base() { cout << "Base destructor\n"; } // 不是 virtual
};

class Derived : public Base {
public:
    Derived() { cout << "Derived constructor\n"; }
    ~Derived() { cout << "Derived destructor\n"; }
};

int main() {
    Base* ptr = new Derived();  // 用 Base 指针指向 Derived 对象
    delete ptr;                 // 只调用 Base 的析构函数
    return 0;
}

二、输出结果


注意:没有调用 Derived 的析构函数

三、问题解释

为什么会这样?

  • Base 的析构函数不是 virtual

  • 当你执行 delete ptr,编译器只看 ptr 的静态类型(即 Base*),它就只调用 ~Base()

  • 因此,不会调用 Derived 的析构函数,可能会导致:

    • Derived 析构中释放的资源没有释放(内存泄漏);
    • 或者 Derived 析构中有清理逻辑没执行(行为错误);

四、修复方法

Base 的析构函数设为 virtual

cpp 复制代码
class Base {
public:
    virtual ~Base() { cout << "Base destructor\n"; }  // virtual 析构
};

正确输出:


五、图示原理(简化)

如果你用 virtual

复制代码
Base vtable:
+----------------+
|  &Base::~Base  |  ← 原始虚函数地址
+----------------+

Derived vtable:
+--------------------+
| &Derived::~Derived | ← 覆盖虚析构函数
+--------------------+

delete ptr 会通过 vtable 跳转到 Derived::~Derived → 再调用 Base::~Base

六、总结

是否 virtual delete 派生类指针时行为 是否内存泄漏
只调用基类析构函数 有可能
调用派生 → 再基类析构 安全

七、经验建议

只要类中有虚函数(即打算支持多态)或你"可能"通过基类指针删除派生类对象,就应该将析构函数声明为 virtual

最好这样写:

cpp 复制代码
class Base {
public:
    virtual ~Base() = default;
};
相关推荐
FQNmxDG4S2 小时前
Java多线程编程:Thread与Runnable的并发控制
java·开发语言
前端老石人2 小时前
HTML 字符引用完全指南
开发语言·前端·html
matlab_xiaowang3 小时前
Redux 入门:JavaScript 可预测状态管理库
开发语言·javascript·其他·ecmascript
虹科网络安全3 小时前
艾体宝干货|数据复制详解:类型、原理与适用场景
java·开发语言·数据库
axng pmje3 小时前
Java语法进阶
java·开发语言·jvm
汉克老师3 小时前
GESP2025年3月认证C++五级( 第三部分编程题(1、平均分配))
c++·算法·贪心算法·排序·gesp5级·gesp五级
老前端的功夫3 小时前
【Java从入门到入土】28:Stream API:告别for循环的新时代
java·开发语言·python
qq_435287923 小时前
第9章 夸父逐日与后羿射日:死循环与进程终止?十个太阳同时值班的并行冲突
java·开发语言·git·死循环·进程终止·并行冲突·夸父逐日
止语Lab4 小时前
从手动到框架:Go DI 演进的三个拐点
开发语言·后端·golang
yaoxin5211234 小时前
397. Java 文件操作基础 - 创建常规文件与临时文件
java·开发语言·python