为什么首先销毁包含的对象?

saf*_*f32 4 perl

在下面的代码片段中,类的对象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阻塞之前,因此在全球销毁阶段之前.(将打印添加到DESTROYFooBar查看.)