虚析构函数中的异常处理
Exception handling in virtual destructor
我在Stack上分配了两个数据库类对象。我在我自己定义的类中继承了这个数据库类。现在数据库类有一个名为"Close()"的函数,如果关闭该数据库实例失败,则抛出异常。现在,对于客户端透视图,我不希望客户端每次都调用close()来关闭连接,而是我想在数据库类中声明一个虚拟的structor,当对象超出范围时,它将自动关闭连接。现在我面临的问题是,如果我创建两个DB对象,现在尝试删除两者,如果关闭成功,这很好,但如果关闭失败的第一个对象,它抛出一个异常,现在第二个仍然被分配(如果动态分配成员对象),这导致内存泄漏。如何处理这种情况
你不会从析构函数抛出异常。参见:http://www.stroustrup.com/bs_faq2.html#ctor-exceptions
Bjarne quote(你能从d.r t抛出异常吗):
Not really:可以在析构函数中抛出异常,但该异常不能离开析构函数;如果析构函数通过抛出退出,则可能发生各种糟糕的事情,因为将违反标准库和语言本身的基本规则。不要这样做。
你可能不想在堆栈上分配任何DB对象,一个安全的,可重用的方法是使用连接池:https://en.wikipedia.org/wiki/Object_pool_pattern
像这样的,每个约定对象的销毁是在程序存在时进行的,在那里您可以将关闭作为池的整体部分来处理,而不是在一些随机函数
您可能应该有一个类用于保存一个数据库连接,另一个类用于保存第一个数据库连接的两个实例。由于我认为数据库的创建也可能失败,因此将每个连接放在自己的类中(带有自己的析构函数)将非常好地处理部分构造/析构。
此外,如果析构函数抛出,您可以做的事情很少(除了记录条件)。
不要从析构函数抛出异常,否则会发生不好的事情,使用shutdown()
方法并在析构函数外部调用它。大多数c++的东西都是在析构函数中清理的,如果你从析构函数中抛出,你实际上就停止了清理,你最终会得到一个未定义状态的c++程序:
class Database{
std::vector<int> v;
connection c;
public:
~Database(){
c.close(); //ouch throws v don't get deallocated. (neither c)
}
};
可以改成:
class Database{
std::vector<int> v;
connection c;
public:
~Database(){
// v deallocated here
}
void shutdown(){
c.close();
}
};
main.cpp
int main(){
Database d;
d.shutdown(); //even if d throws, d destructor will be called.
//and as consequence of d destructor also c & v
//destructors are called.
return 0;
}
因为你有两个数据库
int main(){
Database d1,d2;
try{
d1.shutdown();
}catch( /** correct exception type*/){
//error handling for 1
}
try{
d2.shutdown();
}catch( /** correct exception type*/){
//error handling for 2
}
//both destructors called
return 0;
}
如果close
失败,无论如何都没有好的恢复路径,您最好记录错误,然后继续,就好像它成功了一样。因此,我建议您在析构函数的try
块中调用close
,并在相应的catch
块中记录错误。析构函数可以正常完成。
正如上面@David提到的,析构函数永远不应该泄漏异常,这是因为当异常发生时调用析构函数,而异常中的异常导致崩溃。
永远不应该在析构函数调用中抛出异常。不应该调用任何可能导致它们出现的东西,否则,你会破坏你的类安全。
你应该添加一个函数来检查数据库对象是否可以"关闭",而不是一个异常。如果你想象你只是不能调用函数中的析构函数,可能会抛出异常,你会找到解决方案。
我的选择是不使用析构函数来销毁关联的对象,如果有可能不允许这样做的话。
析构函数仅用于释放内部对象资源。您可以创建类似resource manager
的东西,它将存储指向您需要控制的所有对象的指针。这些可能是shared pointers
。让这个类来定义你的行为,而不是对象本身。
- 哪种方法更适合处理虚拟析构函数?
- 在析构函数内部处理异常(但不抛出)
- 在 postOrderDelete 上调用析构函数时引发的异常
- 为什么在析构函数中引发异常时不调用重载删除
- 文件流析构函数是否可以在C++中引发异常?
- 为什么没有捕获我来自析构函数的异常
- 对象析构函数在多线程处理时不断被调用,但该对象并未超出范围
- 析构函数中的互斥锁C++在 Python 中调用 exit() 时会导致异常
- 如何释放C++异常类析构函数中的变量
- 在由于异常而展开时处理C++析构函数中的pthread取消点
- c++中的Guard,在main中未处理异常时不调用析构函数
- 堆栈异常处理和析构函数展开.如何使用这些信息
- 避免对特定异常调用析构函数
- C++11 异常的析构函数允许现在抛出?
- 虚析构函数中的异常处理
- 为什么在抛出异常时析构函数调用两次
- 如何处理析构函数中互斥对象销毁失败的问题
- boost shared_ptr析构函数中出现未处理的异常
- 引发异常的析构函数
- 为什么异常的析构函数被调用两次