析构函数在对象生命周期结束时自动调用:栈对象作用域结束时、堆对象delete时、全局/静态对象程序退出前、临时对象表达式结束时;不能带参数、重载或非virtual,因调用由编译器严格控制。

析构函数什么时候被调用?
析构函数在对象生命周期结束时自动调用,不是你手动触发的。关键看对象在哪声明、怎么创建:
-
栈上对象(如
MyClass obj;):作用域结束时立即调用,比如函数返回前 - 堆上对象(
new MyClass):必须配对使用delete才会触发;漏掉delete就永远不调用,造成资源泄漏 - 全局/静态对象:程序退出前调用,顺序与构造相反
- 临时对象(如函数返回值、类型转换结果):通常在完整表达式结束时销毁,但 C++17 后可能被强制省略(copy elision),此时析构函数甚至不会生成
为什么析构函数不能带参数、不能重载、不能是虚函数以外的其他形式?
因为它的调用完全由编译器控制,语义固定:只做清理,不接受输入,也不应有多种行为分支。
- 不能有参数:调用时机不由你决定,也无法传参
- 不能重载:每个类只能有一个析构函数,名字固定为
~ClassName() - 基类析构函数应声明为
virtual:否则通过基类指针delete派生类对象时,只会调用基类析构,派生类部分资源不释放(典型内存泄漏)
class Base {
public:
virtual ~Base() = default; // 必须加 virtual
};
class Derived : public Base {
int* data = new int[100];
public:
~Derived() { delete[] data; } // 这行不会执行,如果 Base::~Base 不是 virtual
};析构函数里能做什么?哪些操作要特别小心?
它只该做资源释放:关闭文件、释放内存、解除锁、注销回调等。其他逻辑容易出问题:
- 不要抛异常:C++ 标准规定,析构函数中抛出未捕获异常会导致
std::terminate直接终止程序 - 不要调用虚函数:此时虚表指针可能已开始析构,行为未定义(实际常调用到基类版本,但不可靠)
- 避免访问其他成员对象:它们可能已被先析构(成员按声明逆序销毁)
- 不要调用
delete this(除非你 100% 确保对象是 new 出来的且无人再访问)
什么时候需要显式写析构函数?
不是每个类都需要。只有当类持有“外部资源”时才需要自定义析构函数:
立即学习“C++免费学习笔记(深入)”;
- 裸指针管理的堆内存(
int* p = new int;)→ 需delete p; - 打开的文件句柄(
FILE*或int fd)→ 需fclose()或close() - 持有的互斥锁(
pthread_mutex_t)→ 需pthread_mutex_destroy() - 注册的系统回调(如 Windows 的
SetTimer)→ 需对应取消注册
如果只用 std::vector、std::string、智能指针等 RAII 类型,编译器生成的默认析构函数就足够安全——它们内部已封装好自己的清理逻辑。










