Valgrind能检测delete基类指针时派生类析构未执行导致的内存泄漏,通过“definitely lost”报告及调用栈定位问题,但不直接提示虚析构缺失;需配合-g编译、-Wnon-virtual-dtor警告、GDB动态验证和静态代码审查综合排查。

用 valgrind 检查 delete 基类指针时是否跳过派生类析构
valgrind 是最直接的排查手段。它不会告诉你“析构函数没虚”,但会明确报告:某块内存 malloc / new 了,却始终没被 free / delete ——尤其当这块内存是在派生类构造函数里分配、且对应析构逻辑只写在派生类 ~Derived() 里时,泄漏就指向“析构未执行”。
运行命令:valgrind --leak-check=full --show-leak-kinds=all ./your_program
- 重点看
definitely lost块的调用栈,如果栈顶停在基类delete行,而下一层没进到派生类析构函数,就是典型信号 - 配合编译加
-g,能准确定位到哪一行delete ptr;触发了问题 - 注意:valgrind 对虚表跳转不报错,它只管内存归还事实——所以“没报错”不等于“没问题”
静态检查:grep 所有继承链中基类的析构函数声明
别等运行时出事。在代码库里快速扫一遍所有可能被多态使用的基类,确认其析构函数是否带 virtual 关键字。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 搜索模式:
class\s+\w+\s*{[^}]*~\w+\(\)(粗筛),再人工确认是否含virtual - 重点关注名字含
Interface、Base、Handler、Strategy的类,以及被std::unique_ptr<Base>或Base*持有的类 - 如果基类析构函数是空的(
~Base() = default;),也必须显式加上virtual——= default不自动赋予虚性
用 GDB 在 delete 处设断点,单步看实际调用了哪个析构函数
动态验证最可靠。当你怀疑某处 delete ptr; 行为异常,直接进调试器看真实调用路径。
立即学习“C++免费学习笔记(深入)”;
- 在
delete ptr;行下断点,运行到后执行step(不是next) - 如果下一步跳进了基类析构,且之后直接返回,没进派生类
~Derived(),说明虚表没生效 - 用
info vtbl ptr查看当前对象虚表地址,再x/4a *(void**)ptr看前几项是否包含派生类析构函数地址 —— 若没有,就是虚析构缺失 - 注意:GDB 中
ptr类型必须是基类指针(如Base*),不能是auto或派生类类型,否则会绕过虚调用机制
编译期警告:开启 -Wnon-virtual-dtor 并当真处理
gcc/clang 都支持这个警告,但它默认不启用,且很多人忽略了它的严重性。
- 编译加
-Wnon-virtual-dtor(Clang 还可加-Wdelete-non-virtual-dtor) - 警告内容类似:
‘class Base’ has virtual functions but non-virtual destructor - 这不是“建议”,是 C++ 标准隐含的资源安全契约:只要类有虚函数(意味着设计为多态使用),就必须有虚析构
- CI 流水线里应把这类警告设为 error(
-Werror=non-virtual-dtor),避免合入隐患
delete[] data、fclose(fp)、curl_easy_cleanup() 这些关键清理动作全都没发生——资源泄漏就在无声中累积。

















