面试题答案
一键面试#include <memory>
#include <stdexcept>
class MyClass {
public:
MyClass() {
// 假设这里进行资源分配,可能抛出异常
if (someCondition()) {
throw std::runtime_error("Resource allocation failed");
}
}
~MyClass() {
// 资源释放
}
private:
bool someCondition() {
// 模拟条件判断
return true;
}
};
MyClass& createAndReturnMyClass() {
static std::unique_ptr<MyClass> myObj;
if (!myObj) {
try {
myObj.reset(new MyClass());
} catch(...) {
// 异常处理,这里可以记录日志等
throw;
}
}
return *myObj;
}
异常安全性的三个级别
-
基本保证:
- 实现:在
MyClass
的构造函数中,如果资源分配失败抛出异常,MyClass
的析构函数不会被调用,因为对象还未完全构造完成。std::unique_ptr
在超出作用域时会自动调用MyClass
的析构函数来释放资源。在createAndReturnMyClass
函数中,如果new MyClass()
抛出异常,myObj
不会被赋值,不会导致悬空指针,也不会泄露已分配的资源。 - 体现:如果构造
MyClass
对象时抛出异常,程序不会泄露资源,并且其他对象的状态保持不变。
- 实现:在
-
强保证:
- 实现:在
createAndReturnMyClass
函数中,使用try - catch
块捕获异常。如果new MyClass()
抛出异常,myObj
不会被修改,保持之前的状态(如果有的话)。同时,MyClass
的构造函数应该是强异常安全的,即要么成功构造对象并分配好所有资源,要么抛出异常且不影响其他对象和资源。 - 体现:如果构造
MyClass
对象时抛出异常,程序不会泄露资源,并且其他对象的状态保持不变,而且当前操作(构造MyClass
对象)要么完全成功,要么完全失败,不会处于部分完成的状态。
- 实现:在
-
无异常保证:
- 实现:要达到无异常保证,
MyClass
的构造函数和析构函数都必须不抛出异常。同时,createAndReturnMyClass
函数中的new MyClass()
操作也需要确保不会抛出异常(例如通过提前检查资源是否足够等方式)。在实际应用中,可以使用std::nothrow
版本的new
操作符,不过它返回nullptr
而不是抛出异常,需要额外处理。 - 体现:调用
createAndReturnMyClass
函数永远不会抛出异常,保证程序的执行流是可预测的,不会因为异常而导致程序进入未定义状态。
- 实现:要达到无异常保证,