我在Stack上分配了两个Database类对象。我在个人定义的类中继承了这个数据库类。现在,Database类有一个名为“Close()”的函数,如果关闭该数据库实例失败,则抛出异常。现在对于客户端的观点,我不希望Client每次都关闭连接调用close(),而是我想在Database类中声明一个vitrual Desctuctor,它会在对象超出范围时自动关闭连接。 现在我遇到的问题是,如果我创建了两个数据库对象,现在尝试删除两者并且如果两者都关闭成功则没关系,但是如果第一个对象关闭失败则抛出异常,现在仍然分配第二个(如果是动态的话)分配成员对象),这会导致内存泄漏。如何处理这种情况。
答案 0 :(得分:4)
你不会从析构函数中抛出异常!
见:http://www.stroustrup.com/bs_faq2.html#ctor-exceptions
Bjarne引用(你可以从d.tor中抛出异常):
不是真的:您可以在析构函数中抛出异常,但该异常不能离开析构函数;如果析构函数以throw为单位退出,则可能会发生各种不良事件,因为标准库的基本规则和语言本身将被违反。不要这样做。
您可能不希望在堆栈上分配任何数据库对象,一种安全,可重用的方法是使用连接池: https://en.wikipedia.org/wiki/Object_pool_pattern
像这样,每个连接对象的破坏都是在程序存在的情况下,你可以将关闭作为池的组成部分处理,而不是以某种随机函数的扩散方式处理答案 1 :(得分:1)
你可能应该有一个类用于保存一个数据库连接,另一个类包含第一个的两个实例。由于我认为数据库的创建也可能失败,因此在自己的类(使用自己的析构函数)中建立每个连接都会很好地处理部分构造/破坏。
此外,如果一个析构函数抛出,你可以做的很少(除了记录条件)。 Your application is doomed。
答案 2 :(得分:1)
不要从析构函数中抛出异常,发生不好的事情,使用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;
}
因为你有2个数据库
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;
}
答案 3 :(得分:0)
如果close
失败,无论如何都没有好的恢复路径,你最好记录错误,然后继续进行,就好像它成功了。因此,我建议您在析构函数的close
块中调用try
,并在相应的catch
块中记录错误。然后析构函数可以正常完成。
正如@David上面提到的那样,destuctors永远不应该泄漏异常,这是因为异常发生时会调用析构函数,异常中的异常会导致崩溃。
答案 4 :(得分:0)
绝不应该在析构函数调用中抛出异常。 你不应该调用可能导致它们出现的任何内容,否则就会导致你的课堂安全失败。
您应该添加一个函数来检查数据库对象是否可以“关闭”,而不是例外。如果你想象你只是不能在析构函数中调用可能抛出异常的函数,你会找到解决方案。
我的选择是不要使用析构函数来销毁相关对象,如果有可能不允许这样做。
析构函数仅用于释放内部对象资源。您可以创建类似resource manager
的内容,以存储指向您需要控制的所有对象的指针。这些可能是shared pointers
。让这堂课成为你的行为而不是自己的对象。