【发布时间】:2010-03-23 16:38:18
【问题描述】:
假设我有一个必须释放的资源(例如文件句柄或网络套接字):
open my $fh, "<", "filename" or die "Couldn't open filename: $!";
process($fh);
close $fh or die "Couldn't close filename: $!";
假设process 可能会死。然后代码块提前退出,$fh 不会被关闭。
我可以明确检查错误:
open my $fh, "<", "filename" or die "Couldn't open filename: $!";
eval {process($fh)};
my $saved_error = $@;
close $fh or die "Couldn't close filename: $!";
die $saved_error if $saved_error;
但众所周知,这种代码很难正确编写,并且只会在您添加更多资源时变得更加复杂。
在 C++ 中,我将使用 RAII 创建一个拥有资源的对象,并且其析构函数将释放它。这样,我就不必记住释放资源,并且只要 RAII 对象超出范围,资源清理就会正确进行——即使抛出异常也是如此。不幸的是,在 Perl 中,DESTROY 方法不适合此目的,因为无法保证何时调用它。
是否有 Perlish 方法可以确保即使在出现异常的情况下也能像这样自动释放资源?还是显式错误检查是唯一的选择?
【问题讨论】:
-
Perl 使用引用计数,而不是“真正的”垃圾收集器,因此它是确定性的。您只需要确保您的保护对象不会存储在其他地方。这是通过简单地不将其传递给任何函数或以任何方式使用它来完成的;-)。
-
@Leon 我正要提出相同的论点,但后来我注意到perldoc.perl.org/perltoot.html#Destructors:Perl 关于调用析构函数的正确时间的概念目前没有明确定义,这就是为什么你的析构函数不应依赖于它们何时被调用。
-
对于它的价值,你的例子是一个糟糕的例子,因为
$fh将在它超出范围时被关闭;词法文件句柄是隐式的 RAII。 -
@Sinan Ünür:理论上你是对的,实际上我还没有看到它不能按预期工作的情况。我认为不确定的部分是不同变量被破坏的顺序。
-
@hobbs:文件句柄并不特别。它们也被引用并有自己的(内置)析构函数。