假设您有一段代码:
resource = allocateResource();
try { /* dangerous code here */ }
finally { free(resource); }
我在这里没有提到任何特定的语言,但我想Java,C#和C ++就是很好的例子(假设您在MSVC ++中使用__try
/ __finally
)。
就我个人而言,我认为这不是例外安全的,因为如果在之前有一个例外你输入try
块怎么办?那么你的资源就会泄漏。
我不询问allocateResource
抛出异常,但是在该函数返回后出现异常的情况,但分配 resource
之前。
答案 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
}
}
答案 5 :(得分:0)
我认为你在回答自己的问题。如果allocateResource
分配然后在将资源分配给变量之前抛出异常,则资源将泄漏,并且try/finally
块无法执行任何操作,因为try/finally
阻塞了大多数语言(包括Java和C#)实际上知道关于你在其中使用的资源。
因此,为了try/finally
有效allocateResource
必须以某种方式保证是原子的;要么无误地分配和分配给变量,要么根本不分配并失败。由于没有这样的保证(特别是考虑到不可预测的线程死亡),因此try/finally
块不能有效安全。
某些语言开始支持知道有关资源的using
或with
条款,因此可以安全地关闭它们(尽管这取决于实施解释器/编译器/运行时等。)
答案 6 :(得分:0)
在C#中,任何托管和未引用的资源都会在下次运行时被垃圾收集,所以你没有问题。