10

Scalar::Util::weaken说:

注意:复制弱引用会创建一个正常的强引用。

我不明白为什么 Perl 会这样处理它。在我的应用程序中,我习惯于 weaken打破循环。有时,如果 Perl 不这样做,我必须削弱已经很弱的引用。

4

3 回答 3

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被清除时会意外地被释放。这将打破当您复制引用时,它至少会与副本一样长的期望。

简而言之,如果弱引用在分配中持续存在,它将迫使您在代码中乱扔无数弱点检查,并且需要其他方法来解除变量的弱化,所有这些都是为了避免不可避免的变量自杀问题。

于 2010-12-16T21:24:06.623 回答
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,但仍然很难判断您为什么取消引用只是为了获取新的引用。下一位维护者将尝试“修复”您的代码。

于 2010-12-16T20:01:07.930 回答
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

如果您想创建一个将弱引用作为参数并返回该引用的弱化副本的子例程,则使用上面显示的代码很容易。

于 2010-12-16T18:45:54.703 回答