Perl 具有强引用的对象在引用超出范围之前被销毁?
我有以下Perl代码:Perl 具有强引用的对象在引用超出范围之前被销毁?,perl,oop,destructor,weak-references,Perl,Oop,Destructor,Weak References,我有以下Perl代码: #!/usr/bin/perl use strict; use warnings; # Parent object package Parent; { use Moose; has 'children' => (is => 'rw', isa => 'ArrayRef[Child]', default => sub { [] }); } # Child object package Child; { use Moose
#!/usr/bin/perl
use strict;
use warnings;
# Parent object
package Parent;
{
use Moose;
has 'children' => (is => 'rw', isa => 'ArrayRef[Child]', default => sub { [] });
}
# Child object
package Child;
{
use Moose;
has 'parent' => (is => 'ro', isa => 'Parent', required => 1);
# Child DEMOLISHER!!!! >:)
sub DEMOLISH {
my ($self) = @_;
# Loop through the known children of the parent
for my $index (0 .. $#{$self->parent->children()}) {
# Remove the destroyed child
if ($self->parent->children->[$index] == $self) {
splice @{$self->parent->children()}, $index, 1;
return;
}
}
}
}
package Test;
{
use Scalar::Util qw(weaken);
use Data::Dumper;
# Create a parent object
my $parent = Parent->new();
{
# Create children (with STRONG refs to the parent)
my $child = Child->new('parent' => $parent);
my $child2 = Child->new('parent' => $parent);
my $child3 = Child->new('parent' => $parent);
# Add children to the parents list of children
push @{$parent->children()}, ($child, $child2, $child3);
# Weaken the last childref
weaken($parent->children->[-1]);
# Print the children
print Dumper($parent->children());
}
# The weakened child is out of scope and should be removed
print Dumper($parent->children());
}
此代码创建一个父对象,然后创建3个子对象(每个子对象都具有对父对象的强引用)。然后一个孩子被削弱了。当孩子们超出范围时,预计虚弱的孩子将被销毁并从父母的孩子
数组中移除(哇,听起来很残忍),而其他两个孩子则会留下
但是,运行此代码后,我得到以下输出:
使用以下错误消息:
在全局销毁期间在第28行的数字等式(=)中使用未初始化值。
(在清理中)无法在全局销毁期间对第25行的未定义值调用方法“children”。
现在要澄清这个错误
第25行是这一行:用于我的$index(0..${$self->parent->children()}{
它无法调用$self->parent()
!(这可以通过尝试打印$self->parent()的值来测试)
该错误似乎表明在父对象已销毁之后正在销毁子对象,因此父对象现在未定义。但是正在销毁的子对象包含对父对象的引用,因此在子对象被销毁之前不应允许销毁父对象耶德
这是怎么回事?我不太明白你想说什么?代码是有效的,我只是想知道为什么它声称父对象不再存在。它不应该允许父对象被销毁,直到所有子对象都被销毁。实际上,其他两个子对象也不应该被销毁,因为父对象包含strong对这两个对象的引用。您有一个内存引用周期导致内存泄漏。但是泄漏的对象仍然在程序退出时被释放。但是由于它们没有被正确释放,它们可能不会按照您期望的顺序被释放。@ikegami,您是说因为父对象引用子对象,而2个非弱子对象引用pa吗请注意,Perl不知道在脚本末尾首先销毁哪一个,所以它只选择了一个?我没有研究代码来确定泄漏是什么,但是您的对象在声明词汇表的块结束后仍然存在,因为它们在全局销毁期间被释放,而全局销毁是在文件完成之后发生的正在执行。{$parent->children()}
会更惯用。map
的预期用途是将一个列表转换为另一个列表。我不完全明白你想说什么?代码是有效的。我只是想知道为什么它声称父对象不再存在。它不应该允许父对象被销毁,直到所有的子对象都被销毁。实际上e其他2个子对象也不应被销毁,因为父对象包含对它们的强引用。您有一个内存引用周期,导致内存泄漏。但是泄漏的对象仍然在程序退出时被释放。但是由于它们没有被正确释放,它们可能不会按您期望的顺序被释放。@ikegami,您是说since父级引用子级,2个非弱子级引用父级,Perl在脚本末尾不知道首先销毁哪一个,所以它只选择了一个?我没有研究代码来确定泄漏是什么,但是您的对象在声明词典的块末尾仍然存在,因为它们是在全局销毁期间获得释放,这发生在文件完成执行之后。弱化($)@{$parent->children()};将更为惯用。map
的预期用途是将一个列表转换为另一个列表。