DESTROY вызывается в неожиданной последовательности

Я начал замечать что-то странное вScope::Guard.

  • Если я отменяю определение переменной $guardкак самого последнего оператора в подпрограмме, подпрограмма охранника получает позвонили позже, чем я ожидал.
  • Если я не буду его определять, или если я что-то сделаю (все, что угодно )после undef $guard, вызывается, когда ссылка выходит из объем, как задокументировано. Интересно, почему.

Код также можно найти здесь

my $sClass = 'SGuard';
# Uncomment to use Scope::Guard instead:
# use Scope::Guard; $sClass = 'Scope::Guard';

package SGuard;
sub new {
    my ($class, $sub) = @_;
    return bless { sub => $sub }, $class;
}

sub DESTROY {
    my ($self) = @_;
    $self->{sub}->();
}

package main;
sub mySub {
    my $mySubGuard = $sClass->new(sub { 
         print "shouldDestroyFirst\n" 
    });

    # Do something - any no-op will do.
    undef;

    # Comment out this line and it works
    undef $mySubGuard;

    # Or uncomment the next undef line and it works. Any statement(s) or
    # no-ops will do but we test the return value of mySub to make sure it
    # doesn't return a reference, so undef...

    # undef;
}
{
    my $scopeGuard = $sClass->new(sub { 
        print "shouldDestroyLast\n" 
    });

    # Check that mySub returns undef to ensure the reference *did* go out
    # of scope
    printf "mySub returned a %sdefined value\n", defined mySub() ? "" : "un";
}
print "done\n";

В коде я сделал свой собственный бедный -мужскойScope::Guard(SGuardвыше )просто чтобы сделать пример максимально простым. Вы также можете использоватьScope::Guard и получить точно такие же результаты, неожиданные, по крайней мере, для меня.

Я ожидаю, что $mySubGuardвнутри mySub()должен быть уничтожен первым. и $scopeGuardв области, которая вызывает mySub(), должны быть уничтожены прошлой. И так получите результат вида:

 shouldDestroyFirst
 mySub returned a undefined value
 shouldDestroyLast
 done

Я получаю вывод выше, если использую строку undef $mySubGuardв mySub. Если я не использую строку undef $mySubGuardв mySub, я получаю вывод ниже:

mySub returned a undefined value
shouldDestroyLast
shouldDestroyFirst
done

Итак, похоже, что $mySubGuardиз mySub()уничтожен. после того, как переменные, локальные для внешней области, будут уничтожены.

Почему поведение отличается только потому, что я не определяю переменную, которая вот-вот перейдет? все-таки выходит за рамки? И какая разница, сделано ли что-то после?

8
задан Peter V. Mørch 8 January 2013 в 11:49
поделиться