【问题标题】:How to release resources used by an API when an exception occurs in constructor?构造函数发生异常时如何释放API使用的资源?
【发布时间】:2018-04-06 12:19:15
【问题描述】:

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

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

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

【问题讨论】:

  • RAII,总是RAII。也许你在构造函数中做了很多事情?也许您的设计可能需要一些工作?
  • 此外,您可以在构造函数中捕获、清理,然后重新抛出异常。不是很好的设计,但可以做到。
  • d'tor 没有被调用,因为对象没有被构造。你有一个设计缺陷,并且似乎有意避免所有可以修复它的做法。
  • 您可以清理在抛出异常之前创建的所有内容。 (至少对于这个简单的例子)。
  • @BDL "(除非你将每个 OpenGL 对象都包装在一个 C++ 类对象中)" 这正是 C++ RAII(即 0/5 规则)的方式。

标签: c++ opengl glfw


【解决方案1】:

可以执行以下操作:

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

但显然,这很丑。

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

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 的构造函数和析构函数现在是编译器生成的。在正常使用中,C++会按照声明的顺序初始化成员lib1lib2、...,并以相反的顺序销毁它们。如果任何成员的构造函数抛出异常,C++ 知道在初始化包含A 时销毁它已经创建的所有其他成员。比如Lib2::Lib2()抛出,C++会自动调用Lib1::~Lib1()

【讨论】:

  • 谢谢你,这对我帮助很大。我有一个问题:如果我在 A 类中有一个 init() 方法并将所有 B()、B1()、... 放入 init(),那么我在创建 A 类的对象后调用 init(),这个方法抛出异常而不是构造函数,然后调用该对象的析构函数。我可以用这个吗?或者这很糟糕?
  • @Hope 这并不能真正解决任何问题。 A 的析构函数如何知道哪些初始化确实发生了,哪些没有实际发生?某些代码也可以捕获来自init 的异常,但A 对象仍然存在。
  • 谢谢,你的解释救了我:)。如果我有两种初始化方法,glfwInit()(用于初始化库),glfwCreateWindow()(用于创建上下文和窗口)和两种释放资源的方法,glfwTerminate()(关闭库),glfwDestroyWindow()(关闭窗口,上下文),这些方法都在GLFW库中,那么我需要在A里面创建两个类(Lib1,Lib2)?
猜你喜欢
  • 2019-10-12
  • 2019-08-12
  • 1970-01-01
  • 2013-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多