虚析构函数

时间:2015-07-16 12:43:46

标签: c++

我在Stack上分配了两个Database类对象。我在个人定义的类中继承了这个数据库类。现在,Database类有一个名为“Close()”的函数,如果关闭该数据库实例失败,则抛出异常。现在对于客户端的观点,我不希望Client每次都关闭连接调用close(),而是我想在Database类中声明一个vitrual Desctuctor,它会在对象超出范围时自动关闭连接。 现在我遇到的问题是,如果我创建了两个数据库对象,现在尝试删除两者并且如果两者都关闭成功则没关系,但是如果第一个对象关闭失败则抛出异常,现在仍然分配第二个(如果是动态的话)分配成员对象),这会导致内存泄漏。如何处理这种情况。

5 个答案:

答案 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。让这堂课成为你的行为而不是自己的对象。