Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Situations where Perl would not call DESTROY on object destruction?

Tags:

perl

This is a perplexing problem that a co-worker of mine has. And I have not been able to work out the cause, either.

The short version is, in a class he has written, which has a DESTROY destructor/method defined, DESTROY is not getting called when the object is destroyed. It is not getting called at the point where we would have thought the object goes out of scope. And while we considered that maybe there was a dangling reference to it somewhere, it isn't being called at script exit, either. We've littered the class and the script with debugging print statements, and even made an explicit call to it in an END block just to verify that we hadn't somehow put it in the wrong namespace. (We hadn't. The explicit call triggered all the print statements as expected.)

So I'm puzzled by this, and am just as interested in the answer as he is. What situations might lead to this behavior? The script in question is exiting cleanly - there is no call to POSIX::_exit or anything like that. The only "variable" in this is that the class is using Class::MethodMaker to define some accessors and the constructor. However, there are no references in the Class::MethodMaker docs to having interaction with (or overriding) a class DESTROY method.

like image 258
rjray Avatar asked Dec 12 '22 02:12

rjray


1 Answers

Without seeing the code, one cannot know what is going wrong. But I can imagine a scenario where it would seem like your DESTROY() method is not called:

#!/usr/bin/perl

use strict;
use warnings;

sub DESTROY {
    die {};
    print "DESTROY\n";
}

{
    print "creating object...\n";
    my $obj = bless {};
    print "it goes out of scope...\n";
}

print "object is out of scope\n";

This script prints:

creating object...
it goes out of scope...
object is out of scope

Probably, the error is not as obvious as in this example. The die() call could be deep in the DESTROY code.

The die() call may be caused by some condition that you did not think of. Objects are undef'ed in arbitrary order during global destruction:

#!/usr/bin/perl

use strict;
use warnings;

sub DESTROY {
    die {} if ! defined $_[0]->[0];
    print "$_[0]->DESTROY()\n";
}

print "creating objects...\n";
my $x = bless [];
my $y = bless [$x];
$x->[0] = $y;
print "before global destruction...\n";

The circular references are not necessarry for this to happen. One of the objects checks if it can access another object. If the access fails, an exception is thrown.

h2h, Matthias

like image 131
Matthias Avatar answered May 10 '23 15:05

Matthias