1. 析构函数基础与常见误区
在C++开发中,析构函数(Destructor)是类成员函数中最为特殊的一类。它负责在对象生命周期结束时自动执行清理工作,比如释放堆内存、关闭文件句柄、断开网络连接等资源管理操作。看似简单的析构函数,却隐藏着许多容易踩坑的细节。
1.1 析构函数的默认行为
从C++11标准开始,析构函数默认被标记为noexcept(true)。这意味着编译器会假设析构函数不会抛出任何异常。这种设计背后的逻辑是:在对象销毁过程中,如果发生异常且无法处理,程序将处于不确定状态,直接终止可能是更安全的选择。
cpp复制class ResourceHolder {
public:
~ResourceHolder() = default; // 实际等同于 noexcept(true)
};
这个默认行为会导致一个严重问题:如果在析构函数中抛出异常且未被捕获,程序会立即调用std::terminate()终止,而不是正常传播异常。这在调试时可能表现为程序突然退出,而没有任何有用的错误信息。
1.2 虚析构函数的重要性
当存在继承关系时,基类析构函数必须声明为虚函数(virtual),否则通过基类指针删除派生类对象会导致资源泄漏:
cpp复制class Base {
public:
~Base() { /* 非虚析构函数 */ }
};
class Derived : public Base {
int* data;
public:
Derived() : data(new int[100]) {}
~Derived() { delete[] data; } // 永远不会被调用!
};
Base* obj = new Derived();
delete obj; // 仅调用Base::~Base(), 内存泄漏!
正确的做法是将基类析构函数声明为virtual:
cpp复制class Base {
public:
virtual ~Base() = default;
};
提示:即使基类没有任何其他虚函数,只要可能被继承,就应该为其添加虚析构函数。这是C++中著名的"基类析构函数必须为虚"规则。
