如果我知道我的函数不会抛出异常,我应该在析构函数中放置try ... catch块

时间:2009-12-07 08:35:59

标签: c++ exception-handling destructor

我知道析构函数不应该抛出异常。

http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.13

我有以下代码:

~a()
{
    cleanup();
}

// I do not expect exception being thrown in this function.
// If exception really happen, I know that it is something not recoverable.
void a::cleaup()
{
    delete p;
}

在我的静态源代码分析中,它抱怨我将以这种方式调用清理函数:

~a()
{
    try {
        cleanup();
    }
    catch(...) {
        // What to do? Print out some logging message?
    }
}

// I do not expect exception being thrown in this function.
// If exception really happen, I know that it is something not recoverable.
void a::cleaup()
{
    delete p;
}

我不确定这是一个好习惯,在析构函数中放置try ... catch块,只要它调用函数。作为:

(1)如果清理功能能够抛出异常,我知道发生了一些不好的事情。我更喜欢fail-fast。也就是说,让整个系统崩溃,让程序员调试它。

(2)进入和退出try ... catch块时发生开销。

(3)代码看起来很麻烦,在类的析构函数中有很多try ... catch块。

我可能会错过其他一些观点,为什么要尝试......抓住障碍应该到位。

感谢。

6 个答案:

答案 0 :(得分:3)

由于delete不会抛出,cleanup也不会抛出,因此无需将调用放入try-catch。

由于您的静态分析工具可能很难搞清楚,或许您可以通过将cleanup声明为无投掷来帮助它(这只是猜测)。

void cleanup() throw();

答案 1 :(得分:2)

也许你可以更精确地了解你的清理功能。如果仅在非常罕见的情况下,cleanup()函数是否故意抛出异常?那么你肯定应该在你的析构函数中处理这个案例,因为即使很少见,抛出异常也是cleanup()的预期行为。

至少,您的异常处理代码可能会使您的程序处于定义良好的状态,从而可以优雅地结束您的程序。

或者你的意思是清理()可能会抛出,例如一个OutOfMemoryException或另一个你从未在其他地方处理过的运行时异常?然后我也会在析构函数中省略异常处理。在这种特殊情况下,您的应用程序可能无法运行其错误处理代码。您应该尽一切可能确保即使报告或正确记录此类异常也是如此。

编辑:

现在你已经展示了cleanup的实现,Neil已经回答了你的问题。 delete p不能抛出,因此a::cleanup只要p的析构函数不抛出就不会抛出。{/ p>

答案 2 :(得分:1)

当然,这个问题确实存在于p的析构函数中。在清理()时,你说

delete p;

delete本身不能抛出,因此异常必须来自p的析构函数。在析构函数中,您需要担心使用try块,而不是使用try块。

答案 3 :(得分:1)

从根本上说,当已经处理异常时抛出异常是不安全的。

如果在堆栈展开时调用析构函数,并抛出另一个异常,那么你的线程可以在某些系统(例如Symbian)上立即终止;您的代码计划捕获异常将不会停止该终止 - 您的代码甚至不会被调用。如果您的exception escapes the destructor

,您的帖子肯定会被终止

因此,析构函数中的try {} catch(...) {}不是可移植的,并且当然很棘手。

声音建议永远不会调用可能会在 cleanup 代码中抛出异常的代码,例如析构函数和可能从析构函数调用的任何函数,例如“cleanup()”, close()'或'release_something()'。

原始海报还会查询try-catch的性能。在采用C ++异常的早期,异常处理代码相当昂贵;目前,您的编译器几乎肯定使用零成本异常,这意味着未抛出的异常不会给代码带来运行时性能损失(但当然会略微增加程序的二进制大小)。

答案 4 :(得分:1)

由于内存分配或删除,抛出错误通常没有任何意义。无论是否有效,您可以花费大量的工作来处理愚蠢的错误,而不会获得任何好处。

您可能希望在特定情况下执行此操作,但在实践中也没有做太多,如果有问题,您通常需要使用调试器或更完整的工具。

答案 5 :(得分:0)

我从不使用此功能,但异常安全纯粹主义者会说你的cleanup()功能可能会在你没有预料到的情况下抛出。所以这种模式是一种额外安全的技术。

但是,cleanup函数不应该放在第一位。所以我会在cleanup()中放置任何异常处理,而不是在析构函数本身。