注意:复制弱引用会创建一个正常的强引用。
我无法理解为什么Perl会这样处理它。在我的应用程序中,我使用
weaken
打破周期。有时我必须削弱那些已经很弱的引用,如果Perl不这样做的话。
答案 0 :(得分:13)
每次将引用复制到新变量时,引用计数都会递增。复制弱引用或强引用时都是如此。
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
被清除时,哈希会被意外地处理掉。这会打破这样的期望,即当您复制引用时,它至少会与副本一起保留。
简而言之,如果在作业中持续存在弱引用,则会强制您使用无数弱点检查来丢弃代码,并且需要一些其他方法来取消变量,以避免不可避免的变量自杀问题。
答案 1 :(得分:10)
我认为这是一个封装问题。如果第三方库在内部使用弱引用,我的代码不应该提前知道当我复制一个引用它可能会突然消失在我身上时。 Perl通常的期望是,只要存在,ref就会保持有效。当您致电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 (.....
如果你知道ref只能是一种类型,你可以保存if
/ elsif
级联并简单地执行deref-reref,但是仍然更难判断为什么你取消引用只是为了取一个新参考。下一个维护者将尝试“修复”您的代码。
答案 2 :(得分:3)
我不确定为什么这是默认行为,但这里是基于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
如果你想创建一个以弱引用作为参数的子例程并返回该引用的弱化副本,那么使用上面显示的代码就很容易了。