前一天,我在一次采访中遇到了这个问题。所以请指导我。
如果 c++ 中的构造函数抛出异常,如何清理初始化的资源?
诀窍是使用RAII(资源获取即初始化)来管理资源。
如果您有指针成员,则使用智能指针而不是原始指针,一旦构造函数抛出异常,它将自动执行清理工作。
使用在资源被销毁时释放资源的数据成员(又名 RAII)。
例如:
struct TwoStrings {
std::string string1;
std::string string2;
TwoStrings(const std::string &input) : string1(input) {
if (!input[1] == ':') {
throw std::logic_error('not a Windows absolute path');
// yes, absolute paths can begin \\, this is a toy example
}
if (input.back() == '\\') {
string2 = input;
} else {
string2 = input + "\\";
}
}
};
如果构造函数抛出(logic_error
或bad_alloc
),则已经初始化的数据成员string1
被销毁,释放资源。就此而言,string2
它也被破坏了,但如果构造函数抛出 thenstring2
必须仍然是空的,因此没有特别的效果。
string
是管理资源的类的示例,但还有许多其他类。其中最灵活的称为“智能指针”,并且可以配置为管理几乎任何资源,而不仅仅是像这样自行分配的字符数组string
。
当抛出异常时,堆栈将展开到捕获点。结果,所有在其中建造的东西都被摧毁了。
因此,关键是将每个合理的资源包装到一个类中,该类的析构函数负责相关资源的处置。
如果资源是堆分配的对象,则智能指针会执行此操作(在销毁时删除指向的对象),如果资源是打开的文件,则流会在销毁时将其关闭。其他一切都需要自定义包装器。
但请注意,许多“资源”由本身为 void* 的处理程序表示。这也可以通过使用分配的资源进行初始化并指定删除函数来使用智能指针。
技术发挥得更好更多的是品味和机会的问题。
最好的方法是:在构造函数中分配任何资源并在析构函数中释放任何资源。
C++ 中的模板对此非常有帮助,因为我们可以使对象创建原子化。