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

近頃はPerl書いてなかったかというとそんなことなくて、
近年稀に見る頻度で書いてたんだけど、機会があればその成果を発表したいと思います。
それはそうと、今日はArrayValue辺りを学んでみます。

今回は、このページを参考にしました。

CによるPerl拡張入門(α)
http://xsubtut.github.io/

av_push にかぎらず、配列やハッシュに保存するAPIはSVのコピーを行いませんので自分でコピーします。パフォーマンスのためにコピーを省略したい場合は、SvREFCNT_inc でリファレンスカウントを増やしてください。

配列の操作のところに、このように書かれているので、
その意味を確かめるべく、実際にコードを書いてみます。

use v5.14;
use strict;
use warnings;

use Data::Dumper;

use Inline C => q{
    AV * create_array_value(SV *sv)
    {
        AV *array = newAV();
        // SvREFCNT_inc( sv ); <-- これがないとダメ!
        av_push( array, sv );
        return array;
    }

    SV * get_ref_count(SV *sv)
    {
        return newSViv( SvREFCNT(sv) );
    }
};

my $foo = 10;
say 'ref_cnt: ', get_ref_count( $foo );
my $bar = create_array_value( $foo );
say Dumper( \$bar );
say 'ref_cnt: ', get_ref_count( $foo );
shift @{$bar};
say 'ref_cnt: ', get_ref_count( $foo );

11行目をコメントアウトしたまま実行するとこんな感じ。
$ perl aaa.pl
ref_cnt: 1
$VAR1 = \[
10
];

ref_cnt: 1
ref_cnt: 0
Attempt to free unreferenced scalar: SV 0x7fc8a302a560.

なるほど、av_pushではリファレンスカウントは増えないけど、
shiftするとリファレンスカウントが減るので、
SvREFCNT_inc使ってリファレンスカウントを増やす必要があるってことなんですね。

11行目を有効にするとこんな感じ。
$ perl aaa.pl
ref_cnt: 1
$VAR1 = \[
10
];

ref_cnt: 2
ref_cnt: 1

めでたし、めでたし。

Leave a Comment