Try / Finally实际上是异常安全的吗?

时间:2011-06-04 04:55:24

标签: c# java visual-c++ exception-handling exception-safe

假设您有一段代码:

resource = allocateResource();
try { /* dangerous code here  */ }
finally { free(resource); }

我在这里没有提到任何特定的语言,但我想Java,C#和C ++就是很好的例子(假设您在MSVC ++中使用__try / __finally)。

这个例外安全吗?

就我个人而言,我认为这不是例外安全的,因为如果在之前有一个例外你输入try块怎么办?那么你的资源就会泄漏。

但是,我已经看过很多次了,我觉得我错过了什么......我呢?或者这真的不安全吗?


编辑:

询问allocateResource抛出异常,但是在该函数返回后出现异常的情况,但分配 resource之前。

7 个答案:

答案 0 :(得分:6)

  

我不是在询问allocateResource抛出异常,而是一种情况   之后你得到一个例外   该函数已返回,但在分配资源之前。

尝试处理异常安全的这一方面非常麻烦,尤其是因为语言结构不允许您在赋值语句的中间安装finally处理程序。

我对这一切的理由是,如果你无法从函数调用的末尾获得分配给变量,那么你的系统就已经被软化了。当你无法分配变量时,谁在乎你的内存是否泄漏?

答案 1 :(得分:3)

重点是让所有代码都能在<{1}}块中抛出异常 。在你的情况下:

try

否则 - 不,当然不安全。

答案 2 :(得分:2)

在C#的情况下,它被认为是不安全的,因为可以在资源分配和try块的开头之间抛出ThreadAbortException。出于这个原因,C#4改变了using块的扩展以在try内部移动资源分配,finally块使用隐藏的布尔值(或者对null的测试 - 我不记得了确切地说,确定是否实际发生了分配。

答案 3 :(得分:1)

这取决于allocateResource的编写方式。鉴于上面的片段,allocateResource可以产生两个结果: 1)它分配并返回一个资源 2)它除外(因此不返回资源)

因此,如果allocateResource确保在抛出之前不会在内部泄漏任何分配,则上述不会泄漏resource,因为该方法不能同时抛出和返回。

答案 4 :(得分:0)

只有try {}块内的代码是安全的。并且只有正确捕获所有异常。

当然,块外的代码不会,这正是所期望的行为。

请注意,finally {}块中的代码也可以抛出异常,因此您可能需要在finally或catch块中包含try-catch块。

e.g:

try {
    // your code here
} finally {
    try {
        // if the code in finally can throw another exception, you need to catch it inside it
    } catch (Exception e) {
       // probably not much to do besides telling why it failed
    }
} catch (Exception e) {
    try {
        // your error handling routine here
    } catch (Exception e) {
       // probably not much to do besides telling why it failed
    }
}
  • 如果在分配之前抛出异常,则没有任何东西可以释放,因此没有任何泄漏。
  • 如果在分配后发生异常并且内部 try / catch块,那么它将由finally处理
  • 如果在分配之后发生异常并且在 try / catch块之前,则应重新考虑代码,并且应该在块内移动那些有问题的行。

答案 5 :(得分:0)

我认为你在回答自己的问题。如果allocateResource分配然后在将资源分配给变量之前抛出异常,则资源将泄漏,并且try/finally块无法执行任何操作,因为try/finally阻塞了大多数语言(包括Java和C#)实际上知道关于你在其中使用的资源。

因此,为了try/finally有效allocateResource必须以某种方式保证是原子的;要么无误地分配和分配给变量,要么根本不分配并失败。由于没有这样的保证(特别是考虑到不可预测的线程死亡),因此try/finally块不能有效安全。

某些语言开始支持知道有关资源的usingwith条款,因此可以安全地关闭它们(尽管这取决于实施解释器/编译器/运行时等。)

答案 6 :(得分:0)

在C#中,任何托管和未引用的资源都会在下次运行时被垃圾收集,所以你没有问题。