4

这是我的一个同事遇到的一个令人困惑的问题。而且我也无法找出原因。

简短的版本是,在他编写的一个DESTROY定义了析构函数/方法的类中,DESTROY当对象被销毁时不会被调用。它不会在我们认为对象超出范围的时候被调用。虽然我们认为在某处可能存在对它的悬空引用,但它也不会在脚本退出时被调用。我们在类和脚本中乱扔了调试print语句,甚至在一个END块中显式调用它只是为了验证我们没有以某种方式将它放在错误的命名空间中。(我们没有。显式调用print按预期触发了所有语句。)

所以我对此感到困惑,并且和他一样对答案感兴趣。什么情况下可能会导致这种行为?有问题的脚本正在干净地退出 - 没有调用POSIX::_exit或类似的东西。唯一的“变量”是该类Class::MethodMaker用于定义一些访问器和构造函数。但是,文档中没有提及Class::MethodMaker与(或覆盖)类DESTROY方法进行交互。

4

3 回答 3

6

还有另一种不调用 DESTROY 的方法,它没有特别清楚地记录在案。但是,只有在您编写守护程序之类的情况下,它才会影响您。本质上,如果你的进程因为一个信号(甚至是 CTRL-C,实际上是 SIGINT)而死掉,那么它就不会调用 DESTROY 方法。您可以通过使用仅调用 exit() 的信号处理程序来实现它。在下面的示例中,如果程序正常退出或收到 SIGTERM,则调用 DESTROY() 方法:

sub _signal_handler {
  exit(0);
}

sub new {
  my ($class) = @_;
  my $self = {};
  bless $self, $class;
  SIG{'TERM'} = \&_signal_handler;
  return $self;
}

sub DESTROY {
  my ($self) = @_;
  print "Destroy method called\n";
}
于 2012-10-17T17:20:39.487 回答
6

没有看到代码,就无法知道出了什么问题。但我可以想象一个场景,看起来您的 DESTROY() 方法似乎没有被调用:

#!/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";

此脚本打印:

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

很可能,该错误不像此示例中那样明显。die() 调用可能在 DESTROY 代码中很深。

die() 调用可能是由您没有想到的某些情况引起的。对象在全局销毁期间以任意顺序取消定义:

#!/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";

循环引用不是发生这种情况所必需的。其中一个对象检查它是否可以访问另一个对象。如果访问失败,则抛出异常。

h2h,马蒂亚斯

于 2012-06-05T15:08:23.940 回答
1

刚刚发现在一个类中有超过 1 个 DESTROY 子也会导致这种情况,看起来只有最后一个实例被调用。

于 2020-05-04T13:00:46.433 回答