Inline::Cで学ぶperlguts(その2)

前回で、参照カウンタを取得する方法が分かったので、
リファレンスを取得して、参照カウンタがどうなるのか確認してみる。

use v5.14;
use strict;
use warnings;

use Inline C => q{
    SV * get_ref_cnt(SV *sv) {
        SV *ret = newSViv( SvREFCNT(sv) );
        return ret;
    }
    SV * get_reference_inc(SV *sv) {
        SV *ret = newRV_inc( sv );
        return ret;
    }
    SV * get_reference_noinc(SV *sv) {
        SV *ret = newRV_noinc( sv );
        return ret;
    }
};

{
    my $sv1 = 123;
    my $foo = get_reference_inc( $sv1 );

    say 'get_reference_inc';
    say 'REFCNT = ', get_ref_cnt( $sv1 );
    say '${$foo} = ', ${$foo};
    say '\$sv1 = ', \$sv1;
}

{
    my $sv2 = 456;
    my $foo = get_reference_noinc( $sv2 );

    say 'get_reference_noinc';
    say 'REFCNT = ', get_ref_cnt( $sv2 );
    say '${$foo} = ', ${$foo};
    say '\$sv2 = ', \$sv2;
}

$ perl aaa.pl
get_reference_inc
REFCNT = 2
${$foo} = 123
\$sv1 = SCALAR(0x7f80cc828088)
get_reference_noinc
REFCNT = 1
${$foo} = 456
\$sv2 = SCALAR(0x7f80cc8fcb60)
Attempt to free unreferenced scalar: SV 0x7f80cc8fcb60.

リファレンスを取得すると参照カウンタが増えるのは、前回で確認済みだったけど、
参照カウンタを増やさないでリファレンスを取得することも出来る。
けど、結果的に今回は警告(エラー?)が出力されたので使いどころを間違えたみたい。

リファレンスがスコープを抜けて1回、scalar変数がスコープを抜けたで1回、
合わせて2回参照カウンタをデクリメントしてると思うんだけど、
参照カウンタが1しかないのに余計にデクリメントしたことで、
「すでに解放したscalar変数をまた解放しようとしたんだけど?」
みたいな感じのメッセージが出力されたんだと思う。

メモリリークとは異なるけど、今回のケースはメッセージで判別できるので、
安心しておかしなコードが書けますね。

おしまい。

Leave a Comment