析构函数必须是public、无参、无返回值,且不能为const或重载;基类析构应声明为virtual以确保派生类资源正确释放;其核心职责是清理动态资源,禁止抛异常、调用虚函数或重复释放RAII对象。

析构函数必须是 public 且无参无返回值
如果你在类里写了一个带参数的 ~ClassName(),编译器会直接报错:「destructor cannot have parameters」。析构函数由编译器自动调用,时机固定(对象生命周期结束时),所以不能手动传参,也不能重载。它只能是 ~ClassName() 这种签名,且通常应声明为 public —— 如果设为 private 或 protected,会导致栈上对象无法销毁(编译错误)或堆上对象无法 delete(链接错误)。
- 不要写
~MyClass(int x)、virtual ~MyClass() const(const无效) - 基类析构函数建议加
virtual,否则通过基类指针delete派生类对象时,派生类部分不会被析构 - 如果类没写析构函数,编译器会生成默认版本(空实现),但只要涉及动态内存、文件句柄、锁等资源,就必须自己定义
什么时候必须手动释放资源
析构函数的核心职责是「清理」,不是「逻辑处理」。常见需手动干预的资源包括:new 出来的内存、fopen 打开的文件、pthread_mutex_init 创建的锁、Windows 的 CreateThread 句柄等。C++ 不回收这些,不写析构函数就会泄漏。
- 用
new[]分配数组,析构里必须用delete[],不能只写delete - 若类中持有
std::unique_ptr或std::vector,它们自身会自动清理,你不用再管——这是 RAII 的好处,别画蛇添足 - 避免在析构函数里抛异常(C++11 起默认是
noexcept),否则程序可能直接终止;真要处理错误,用日志或断言
析构函数里不能调用虚函数
对象析构时,虚函数表指针会逐步回退到基类状态,此时调用虚函数实际执行的是当前类(正在析构的那个类)的版本,而不是最终派生类的重写版。这和构造过程对称,但容易误以为还能多态。
Derived d;
- 基类子对象总是在派生类成员之后析构(即:派生类成员 → 基类成员)
- 局部对象按定义逆序析构,全局/静态对象按定义逆序、跨编译单元顺序未定义——这点容易引发「静态析构顺序灾难」
- 别在析构函数里访问已被析构的成员(比如在 A 的析构里调用 B 的方法,而 B 在 A 之前声明)
析构函数看着简单,但资源生命周期、继承层次、静态对象三者一叠加,出问题很难调试。最稳妥的做法是:能用智能指针就别裸 new,能用容器就别手管内存,析构体里只做明确必要的清理,别的交给 RAII。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











