MST

星途 面试题库

面试题:C++ 函数返回引用的异常安全性与资源管理类结合

考虑使用 `std::unique_ptr` 来管理 `MyClass` 类中的动态资源。编写一个函数 `MyClass& createAndReturnMyClass()`,该函数在构建 `MyClass` 对象过程中可能抛出异常,要确保无论异常是否发生,资源都能正确管理,并且返回的引用指向的对象状态是合理的。同时说明在这个过程中异常安全性的三个级别(基本保证、强保证、无异常保证)分别如何实现和体现。
10.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
#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;
}

异常安全性的三个级别

  1. 基本保证

    • 实现:在MyClass的构造函数中,如果资源分配失败抛出异常,MyClass的析构函数不会被调用,因为对象还未完全构造完成。std::unique_ptr在超出作用域时会自动调用MyClass的析构函数来释放资源。在createAndReturnMyClass函数中,如果new MyClass()抛出异常,myObj不会被赋值,不会导致悬空指针,也不会泄露已分配的资源。
    • 体现:如果构造MyClass对象时抛出异常,程序不会泄露资源,并且其他对象的状态保持不变。
  2. 强保证

    • 实现:在createAndReturnMyClass函数中,使用try - catch块捕获异常。如果new MyClass()抛出异常,myObj不会被修改,保持之前的状态(如果有的话)。同时,MyClass的构造函数应该是强异常安全的,即要么成功构造对象并分配好所有资源,要么抛出异常且不影响其他对象和资源。
    • 体现:如果构造MyClass对象时抛出异常,程序不会泄露资源,并且其他对象的状态保持不变,而且当前操作(构造MyClass对象)要么完全成功,要么完全失败,不会处于部分完成的状态。
  3. 无异常保证

    • 实现:要达到无异常保证,MyClass的构造函数和析构函数都必须不抛出异常。同时,createAndReturnMyClass函数中的new MyClass()操作也需要确保不会抛出异常(例如通过提前检查资源是否足够等方式)。在实际应用中,可以使用std::nothrow版本的new操作符,不过它返回nullptr而不是抛出异常,需要额外处理。
    • 体现:调用createAndReturnMyClass函数永远不会抛出异常,保证程序的执行流是可预测的,不会因为异常而导致程序进入未定义状态。