如何在 Perl 中自动释放 RAII 风格的资源?
假设我有一个必须释放的资源(例如文件句柄或网络套接字):
open my $fh, "<", "filename" or die "Couldn't open filename: $!";
process($fh);
close $fh or die "Couldn't close filename: $!";
假设进程
可能会死亡。然后代码块提前退出,并且 $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 方法可以确保即使在出现异常的情况下也能像这样自动释放资源?或者显式错误检查是唯一的选择吗?
Say I have a resource (e.g. a filehandle or network socket) which has to be freed:
open my $fh, "<", "filename" or die "Couldn't open filename: $!";
process($fh);
close $fh or die "Couldn't close filename: $!";
Suppose that process
might die. Then the code block exits early, and $fh
doesn't get closed.
I could explicitly check for errors:
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;
but this kind of code is notoriously difficult to get right, and only gets more complicated when you add more resources.
In C++ I would use RAII to create an object which owns the resource, and whose destructor would free it. That way, I don't have to remember to free the resource, and resource cleanup happens correctly as soon as the RAII object goes out of scope - even if an exception is thrown. Unfortunately in Perl a DESTROY
method is unsuitable for this purpose as there are no guarantees for when it will be called.
Is there a Perlish way to ensure resources are automatically freed like this even in the presence of exceptions? Or is explicit error checking the only option?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为这就是 Scope::Guard 的目的。
然而,正如 @Philip 在评论中指出的那样,
Scope::Guard
使用了DESTROY
方法,这对于何时运行作用域退出代码产生了一些不确定性。Hook::Scope
和Sub::ScopeFinalizer
等模块看起来也不错,尽管我从未使用过它们。我确实喜欢 Try::Tiny ,因为它干净的界面和纯粹的简单性,它会帮助您以正确的方式处理异常:
I think that's what Scope::Guard was designed to help with.
However, as @Philip notes in the comments,
Scope::Guard
utilizes theDESTROY
method which creates some uncertainty as to when the scope exit code will be run. Modules such asHook::Scope
andSub::ScopeFinalizer
look fine as well although I have never used them.I do like Try::Tiny for its clean interface and sheer simplicity and it will help you handle exceptions the correct way:
我的模块 Scope::OnExit 正是用于此目的。
My module Scope::OnExit is intended for exactly that.
词法文件句柄的好处是,当它们超出范围时,它们会被关闭(并释放)。所以你可以这样做:
The nice thing about lexical filehandles is that they'll get closed (and freed) when they go out of scope. So you can just do something like this: