如何在构造函数发生异常时释放API占用的资源?

How to release resources used by an API when an exception occurs in constructor?

我有一组使用一些资源的方法 B()、B1()... 和一组释放这些资源的方法 C()、C1()...属于一个API(比如GLFW,OpenGL,...),我把它们放在一个class的构造函数和析构函数中 A:

class A {
public:
  A() {
    B();
    B1();
    ....
    throw 1;
  }
  ~A() {
     C();
     C1();
   }
};

并且当发生异常时,无法调用~A(),因此无法释放此API占用的资源。我不能使用智能指针来确保没有内存泄漏,我也不想因为创建一个无用的对象而在构造函数中使用 try catch 语句。任何人都可以解决这种情况吗?

可以做如下事情:

A::A() {
    B();
    try {
        B1();
        try {
            // ...
        } catch (...) {
            C1();
            throw;
        }
    } catch (...) {
        C();
        throw;
    }
}

但显然,这很丑陋。

更好的方法是更接近资源分配即初始化 (RAII) 模式:确保每个库初始化都由一个 C++ 对象表示。您可以通过使这些单独的对象成为整体 A class.

的成员来保持这种方便
class A {
public:
    A() = default;
    A(const A&) = delete;
    A& operator=(const A&) = delete;
    ~A() = default;
private:
    class Lib1 {
    public:
        Lib1();
        ~Lib1();
    };
    class Lib2 {
    public:
        Lib2();
        ~Lib2();
    };
    // ...
    Lib1 lib1;
    Lib2 lib2;
    // ...
}

注意 A 的构造函数和析构函数现在是 compiler-generated。在通常的使用中,C++ 会按照声明的顺序初始化成员lib1lib2、...,并按照相反的顺序销毁它们。如果任何成员的构造函数抛出异常,C++ 就会销毁它已经创建的所有其他成员,作为初始化包含 A 的一部分。例如,如果 Lib2::Lib2() 抛出,C++ 将自动调用 Lib1::~Lib1().