Подтвердить что ты не робот

Perl: Почему Devel:: Refcount:: refcount и Devel:: Peek:: SvREFCNT не согласны?

Я читал Как мне получить доступ к счету хэша Perl?, и там предлагаются как Devel::Refcount::refcount, так и Devel::Peek::SvREFCNT.

Но они не возвращают одинаковые подсчеты ссылок. Почему это?

Здесь представлен измененный пример из perldoc Devel::Refcount:

use Devel::Peek;
use Devel::Refcount;

my $anon = [];

printf "Anon ARRAY $anon has %d/%d reference\n",
    Devel::Refcount::refcount($anon),
    Devel::Peek::SvREFCNT($anon);

my $otherref = $anon;

printf "Anon ARRAY $anon now has %d/%d references\n",
    Devel::Refcount::refcount($anon),
    Devel::Peek::SvREFCNT($anon);

который печатает:

Anon ARRAY ARRAY(0x8b10818) has 1/1 reference
Anon ARRAY ARRAY(0x8b10818) now has 2/1 references

Обратите внимание на последнее несоответствие 2/1...

(Если окажется, что я не делаю что-то глупое, я добавлю ссылку из Как мне получить доступ к количеству ссылок хеша Perl? здесь)

4b9b3361

Ответ 1

Я не могу сказать, что все это еще не понял, но на ваш вопрос ответственно видно на Devel::Refcount perldoc

СРАВНЕНИЕ С SvREFCNT

Эта функция отличается от Devel:: Peek:: SvREFCNT тем, что SvREFCNT() дает ссылочный счет самого SV-объекта, который он передал, тогда как refcount() дает счетчик объекта, на который указывает. Это позволяет ему также подсчитывать количество ссылок (например, ARRAY, HASH, CODE, GLOB и Regexp).

Рассмотрим следующую примерную программу:

 use Devel::Peek qw( SvREFCNT );
 use Devel::Refcount qw( refcount );

 sub printcount
 {
    my $name = shift;

    printf "%30s has SvREFCNT=%d, refcount=%d\n",
       $name, SvREFCNT($_[0]), refcount($_[0]);
 }

 my $var = [];

 printcount 'Initially, $var', $var;

 my $othervar = $var;

 printcount 'Before CODE ref, $var', $var;
 printcount '$othervar', $othervar;

 my $code = sub { undef $var };

 printcount 'After CODE ref, $var', $var;
 printcount '$othervar', $othervar;

Это приводит к выходу

            Initially, $var has SvREFCNT=1, refcount=1
      Before CODE ref, $var has SvREFCNT=1, refcount=2
                  $othervar has SvREFCNT=1, refcount=2
       After CODE ref, $var has SvREFCNT=2, refcount=2
                  $othervar has SvREFCNT=1, refcount=2

Здесь мы видим, что SvREFCNT() подсчитывает количество ссылок на объект SV, переданных в качестве скалярного значения - $var или $othervar соответственно, тогда как refcount() подсчитывает количество опорных значений, которые указывают на референт object - анонимный ARRAY в этом случае.

Перед созданием ссылки CODE оба $var и $othervar имеют SvREFCNT() из 1, поскольку они существуют только в текущей лексической панели. Анонимный ARRAY имеет refcount() из 2, потому что как $var, так и $othervar хранят ссылку на него.

После создания ссылки CODE переменная $var теперь имеет SvREFCNT() из 2, поскольку она также появляется в лексической панели для нового анонимного блока CODE.

Ответ 2

Devel::Refcount::refcount($anon) возвращает счетчик ссылок, на который ссылается $anon.

Массив ссылается на $anon и на $otherref: 2


Devel::Peek::SvREFCNT($anon) возвращает счетчик ссылок $anon.

Скаляр ссылается на пэд, в котором он находится: 1

Devel:: Peek, похоже, не предоставляет средства для подсчета количества массивов, хэшей и т.д.


$ perl -MDevel::Peek -E'my $aref2 = my $aref1 = []; Dump($aref1);'
SV = IV(0x99eee34) at 0x99eee38
  REFCNT = 1                    <---- Devel::Peek::SvREFCNT
  FLAGS = (PADMY,ROK)
  RV = 0x99d57d0
  SV = PVAV(0x99d6778) at 0x99d57d0
    REFCNT = 2                  <---- Devel::Refcount::refcount
    FLAGS = ()
    ARRAY = 0x0
    FILL = -1
    MAX = -1
    ARYLEN = 0x0
    FLAGS = (REAL)

Perl предоставляет полупоставленный встроенный модуль Internals::SvREFCNT, который работает на скалярах, массивах и хешах.

Internals::SvREFCNT(@$anon) возвращает счетчик ссылок < <29 > .

Массив ссылается на $anon и на $otherref: 2

Вышеуказанное работает только для скаляров, массивов и хешей, и вам нужно использовать правильную сигилу. Если вы просто хотите передать произвольную ссылку, вы можете использовать:

&Internals::SvREFCNT($anon) + 1 возвращает счетчик ссылок, на который ссылается $anon.

Массив ссылается на $anon и на $otherref: 2