问题描述
|
假设您有一段代码,例如:
resource = allocateResource();
try { /* dangerous code here */ }
finally { free(resource); }
我在这里没有提到任何特定的语言,但是我想Java,C#和C ++就是很好的例子(假设您在MSVC ++中使用__try
/__finally
)。
这是异常安全的吗?
我个人认为这不是异常安全的,因为如果在进入ѭ3enter块之前发生异常,该怎么办?然后,您的资源将泄漏。
不过,我已经看过足够多次了,所以我认为我缺少了一些东西……是吗?还是真的不安全?
编辑:
我并不是在问allocateResource
引发异常,而是一种情况,在这种情况下,该函数返回之后但在分配resource
之前得到了异常。
解决方法
我不是在问allocateResource抛出异常,而是一种情况
在那之后你得到一个例外
该函数已返回,但在分配资源之前。
尝试处理异常安全的这一方面非常麻烦,尤其是因为该语言结构不允许您在赋值语句的中间安装final处理程序。
我所有这些的基本原理是,如果您无法从函数调用的结尾到分配给变量,则您的系统已经处于崩溃状态。当您无法分配变量时,谁在乎您是否泄漏内存?
, 关键是要在
try
块中包含所有可能引发异常的代码。在您的情况下:
try
{
resource = allocateResource();
//...
}
finally { free(resource); }
否则-不,当然不安全。
, 对于C#,它被认为是不安全的,因为ThreadAbortException可以在资源分配和try块的开始之间抛出。因此,C#4更改了using
块的扩展以在try内移动资源分配,而finally
块使用了一个隐藏的布尔值(或对null进行测试,我记不清了)确定分配是否实际发生。
, 这取决于allocateResource的编写方式。鉴于上面的allocateResource片段可以导致两个结果:
1)分配并返回资源
2)它除外(因此不返回资源)
因此,如果allocateResource
肯定不会在抛出之前在内部泄漏任何分配,则上述内容也不会泄漏resource
,因为该方法不能同时抛出和返回。
, 只有try {}块中的代码是安全的。并且仅在正确捕获所有异常的情况下。
当然,该块外的代码将不会,而这正是所需的行为。
另请注意,finally {}块中的代码也可能引发异常,因此您可能需要在try或catch块中包括try-catch块。
例如。:
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块之前发生,则应重新考虑代码,并将那些有问题的行移入该块内。
, 我认为您正在回答自己的问题。如果allocateResource
分配然后在将资源分配给变量之前引发异常,则资源将泄漏,try/finally
块对此无能为力,因为大多数语言(包括Java和C#)中的try/finally
块实际上并不了解资源你在他们里面使用。
因此,为了使ѭ14有效,ѭ4必须以某种方式保证是原子性的;要么毫无例外地分配并分配给变量,要么根本没有分配并失败。由于没有这样的保证(特别是考虑到不可预测的线程死亡),因此“ 14”个块不能有效地安全。
一些语言开始支持了解资源的using
或with
子句,因此能够安全地关闭它们(尽管这将取决于解释器/编译器/运行时的实现等)。
, 在C#中,任何托管和未引用的资源都将在下一次运行时被垃圾回收,因此您在那里没有任何问题。