注意:复制弱引用会创建一个普通的、强引用。
我不明白为什么Perl要这样处理。在我的应用程序中,我使用weaken
来打破循环引用。有时我必须削弱本来如果Perl不这样操作已经是弱引用的引用。
注意:复制弱引用会创建一个普通的、强引用。
我不明白为什么Perl要这样处理。在我的应用程序中,我使用weaken
来打破循环引用。有时我必须削弱本来如果Perl不这样操作已经是弱引用的引用。
每当你将一个引用复制到一个新变量中时,引用计数都会增加。这适用于复制弱引用和强引用。
my $obj = {}; # 1 reference to {} stored in $obj
my $copy = $obj; # 2 references
weaken $obj; # 1 reference
此时,如果$copy
超出其作用域,引用计数将降至零,并释放内存。现在假设有以下代码:
my $newref = $obj; # 2 references
undef $copy; # 1 reference
如果 Perl 保留了 $newref
中的弱引用,那么当清除 $copy
时,哈希表会意外地被释放。这将打破一个期望:当你复制一个引用时,它至少会和原引用一样长久。
简而言之,如果弱引用在赋值后仍然存在,就必须在代码中添加大量的弱引用检查,并需要其他的方法来取消弱化变量,以避免不可避免的变量自杀问题。
weaken
时,你基本上已经承诺在使用它之前将采取必要的步骤检查引用是否仍然有效。
作为第二个原因,使弱引用的强复制的接口相当直截了当。my $new_ref = $old_ref; if (isweak($old_ref)) { weaken($new_ref); }
如果弱引用创建了一个弱引用,那么获取强引用的代码会更加复杂。
my $new_ref;
if (ref($old_ref) eq 'ARRAY') {
$new_ref = \@{$old_ref};
}
elsif (ref($old_ref) eq 'HASH') {
$new_ref = \%{$old_ref};
}
elsif (.....
如果您知道引用只能是一种类型,那么您可以省略if / elsif级联,并简单地执行deref-reref,但是仍然很难判断为什么要取消引用,然后再重新引用,下一个维护者将尝试“修复”您的代码。我不确定为什么这是默认行为,但是以下解决方案基于来自Scalar::Util文档的代码:
$ref = \$foo;
$weak = isweak($ref); # false
weaken($ref);
$weak = isweak($ref); # true
# copying a weak reference creates a new strong one
$copy = $ref;
$weak = isweak($copy); # false
# the solution is simply to weaken the copy
$weaken($copy);
$weak = isweak($copy); # true