在下面的代码片段中,类的对象Foo包含对类对象的引用Bar.我希望Foo对象在Bar对象之前被销毁.不幸的是,这并不总是发生.奇怪的是,我在不同的系统上得到了不同的行为:在我的笔记本电脑和台式机上,代码总能正常运行,而在我尝试的2个VPS上,析构函数以相反的顺序运行(大多数时候).所有四个系统都运行相同版本的perl(x86_64 linux上为5.20.2).
此外,这仅在子(abcd下面称为)包含Foo对象的引用时发生.如果我删除它,问题就会消失.
#!/usr/bin/perl
use strict;
use warnings;
my $foo = Foo->new;
sub abcd {
$foo;
}
####################
package Foo;
sub new {
bless {bar => Bar->new}, 'Foo';
}
sub DESTROY {
my ($self) = @_;
defined $self->{bar} or print "bar is undefined, this should not happen\n";
}
####################
package Bar;
sub new {
bless {}, 'Bar';
}
Run Code Online (Sandbox Code Playgroud)
zdi*_*dim 10
当涉及到全球销毁时,就会在程序退出时发生,这perlobj一点很清楚
在程序退出之前在全局销毁期间销毁对象的顺序是不可预测的.
没有sub abcd你发布的测试程序就是这种情况.使用sub,对象的最后一个引用位于sub 内部,因此它也会到达全局销毁.(在这两种情况下我也会得到不同的行为,但鉴于上述引用,这是没有意义的.)
因此,在这两种情况下,无论有没有sub,对象都会以不可预测的顺序被破坏.
当一个对象因为最后一次引用超出范围而被销毁时,情况会有所不同.要查看此类行为,我们可以添加undef $foo;为最后一行,以触发受控破坏
my $foo = Foo->new;
undef $foo;
END { say "END block." }
sub abcd { $foo; }
Run Code Online (Sandbox Code Playgroud)
这导致Foo首先被破坏,有或没有sub.它也发生在END阻塞之前,因此在全球销毁阶段之前.(将打印添加到DESTROY中Foo并Bar查看.)