Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the contained object destroyed first?

Tags:

perl

In the code snippet below, the object of class Foo contains a reference to an object of class Bar. I would expect that the Foo object is destroyed before the Bar object. Unfortunately, this doesn't always happen. Strangely enough, I get different behaviors on differenct systems: on my laptop and desktop, the code always runs correctly, whereas on 2 VPSs that I tried, the destructors are ran in reverse order (most of the time). All four systems run the same version of perl (5.20.2 on x86_64 linux).

Also, this only happens when a sub (called abcd below) contains a reference to the Foo object. If I remove that, the problem goes away.

#!/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';
}
like image 538
safsaf32 Avatar asked Jan 06 '23 13:01

safsaf32


1 Answers

When it comes to global destruction, which happens as the program is exiting, perlobj is clear

The order in which objects are destroyed during the global destruction before the program exits is unpredictable.

This is clearly the case without the sub abcd in your posted test program. With the sub, the last reference to the object is inside the sub so it reaches the global destruction as well. (I also get different behavior in the two cases, but this is meaningless given the above quote.)

Thus in both cases, with or without the sub, the objects are destroyed in an unpredictable order.

When an object is destroyed because the last reference to it went out of scope, things are different. To see such behavior we can add undef $foo; as the last line, to trigger controlled destruction

my $foo = Foo->new;

undef $foo;

END { say "END block." }

sub abcd { $foo; }

This results in Foo being destroyed first, with and without the sub. It also happens before the END block and before the global destruction phase. (Add prints to DESTROY in Foo and Bar to see.)

like image 126
zdim Avatar answered Jan 08 '23 02:01

zdim