如何在构造函数发生异常时释放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++ 会按照声明的顺序初始化成员lib1
、lib2
、...,并按照相反的顺序销毁它们。如果任何成员的构造函数抛出异常,C++ 就会销毁它已经创建的所有其他成员,作为初始化包含 A
的一部分。例如,如果 Lib2::Lib2()
抛出,C++ 将自动调用 Lib1::~Lib1()
.
我有一组使用一些资源的方法 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++ 会按照声明的顺序初始化成员lib1
、lib2
、...,并按照相反的顺序销毁它们。如果任何成员的构造函数抛出异常,C++ 就会销毁它已经创建的所有其他成员,作为初始化包含 A
的一部分。例如,如果 Lib2::Lib2()
抛出,C++ 将自动调用 Lib1::~Lib1()
.