2010-12-16 6 views
10

Scalar::Util::weaken言う:Perlでは、弱い参照をコピーすると、普通の強い参照が作成されるのはなぜですか?

注:弱参照をコピーすると、通常、強い、参照を作成します。

なぜこのようにPerlがそれを処理するのか理解できません。私のアプリケーションでは、サイクルを中断するために weakenを使用します。時にはPerlがこのように行動しないなら、すでに弱い参照を弱める必要があります。

答えて

10

これはカプセル化の問題だと思います。第三者図書館が内部的に弱い参照を使用している場合、私のコードは、私が突然私の上で消えるかもしれない参照のコピーを作成することを事前に知っていると予想されるべきではありません。 Perlでの通常の期待は、refは存在する限り有効であるということです。 weakenに電話するときは、基本的には、参照がまだ有効であることを確認するために必要な手順を実行することを約束しています。

弱いrefの強力なコピーを弱めるインタフェースがかなりストレートです。

弱いrefが弱いrefを作成した場合に同じことをするコードは、もう少し複雑です。あなたが知っている場合

my $new_ref; 
if (ref($old_ref) eq 'ARRAY') { 
    $new_ref = \@{$old_ref}; 
} 
elsif (ref($old_ref) eq 'HASH') { 
    $new_ref = \%{$old_ref}; 
} 
elsif (..... 

refは唯一あなたがif/elsifにカスケードを保存し、単にDEREF-rerefを行うことができますいずれかのタイプにすることができますが、あなただけの新しい参照を取るために間接参照理由を判断するのはまだ難しいです。次のメンテナーはあなたのコードを修正しようとします。

3

これはデフォルトの動作ですが、ここではScalar::Utilドキュメントからのコードをベースにしたソリューションである理由私はよく分からない:

$ref = \$foo; 
$weak = isweak($ref);    # false 
weaken($ref); 
$weak = isweak($ref);    # true 

# copying a weak reference creates a new strong one 
$copy = $ref; 
$weak = isweak($copy);    # false 

# the solution is simply to weaken the copy 
$weaken($copy); 
$weak = isweak($copy);    # true 

あなたが引数として弱い参照を取ったサブルーチンを作りたい場合その参照の弱いコピーを返しました。これは上記のコードを使用すると簡単になります。

+0

..サブルーチンは弱い参照を返すことはできますか?サブルーティン内で作成された弱められた参照は、その参照がサブルーチンの終了時に範囲外になると破棄されると思われます。 – Dancrumb

+0

暗黙のコピーで弱い参照結果を返さない(その結果、返される)? – Cameron

+2

@Dancrumb、@Cameron、弱い参照を格納するオーバーロードされたオブジェクトを返すことができます。 – ysth

12

参照を新しい変数にコピーすると、参照カウントが増分されます。これは、弱いまたは強い参照をコピーする場合に当てはまります。この時点で

my $obj = {}; # 1 reference to {} stored in $obj 

my $copy = $obj; # 2 references 

weaken $obj;  # 1 reference 

$copyがスコープ外になった場合、参照カウントがゼロに落ちる、とメモリが解放されます。ここで、次のコードを前提としています

my $newref = $obj; # 2 references 

undef $copy;  # 1 reference 

Perlは$newrefで弱い参照を保存した場合$copyがクリアされたときに、その後、ハッシュが突然dealocatedされるだろう。これは、あなたが参照をコピーするとき、それがコピーと同じくらい長く留まるという期待を破ります。つまり、弱い参照が代入を超えて永続的に残っていれば、無限の弱点チェックでコードを捨てることになり、変数を失うために何か別の方法が必要になり、必然的に変化する自殺問題を回避する必要があります。

関連する問題