ようこそ ゲスト さん、新規登録(無料)して気になる疑問を解決しませんか?

質問

質問者:japanrail 配列要素へのリファレンスと、要素の追加・削除について
困り度:
  • 困っています
ActivePerl v5.8.8 build 820 を使用しています。

配列要素へのリファレンスを取得し、その後要素の追加又は削除を行った場合
元の要素を参照し続けます。

(1) 要素の追加
@list = qw/a b c d/;
$p = \$list[1];
print("$$p\n");
splice(@list, 1, 0, 'x');
print("$$p\n");
# 'b' が表示される
# $list[2] を参照 ($list[1] ではない)

(2) 要素の削除
@list = qw/a b c d/;
$p = \$list[1];
print("$$p\n");
splice(@list, 1, 1);
print("$$p\n");
# 'b' が表示される

質問1
これは perl の仕様としての動作でしょうか? それとも、実行系やバージョン
などの環境に依存するものでしょうか?

質問2
要素の削除の場合、削除直後なのでたまたま元の値が表示されただけで、
削除した要素 'b' が格納されたメモリ空間はいつ上書きされるかわからない
状態なのでしょうか? それとも、上書きされることはないのでしょうか?
質問投稿日時:08/03/13 12:41
質問番号:3858831
この質問に対する回答は締め切られました。
最新から表示回答順に表示良回答のみ表示

回答

良回答20pt

回答者:sakusaker7 おそらく規格書のような形でのきちんと明文化されたものはないと思います。
その上で、

ドキュメント(perlguts.pod)とソース(pp.c, av.c)を見た感じでは、メジャーバージョンが同じならおそらく
一貫した動作になると思われますし、5.6以降とか言う形でも
矛盾した動作はないと思います。
それ以前は確かめるのも大変なのでパス。

Perlの参照は、Cのポインタとは違うものです。ですから

$p = \$list[1];
print("$$p\n");
splice(@list, 1, 0, 'x');
print("$$p\n");
# 'b' が表示される
# $list[2] を参照 ($list[1] ではない)

ここでの $p は $list[1]のアドレスを抱えているわけではありません。
実体そのものを指し示しています。
ですから、spliceによって配列内で移動があったとしても
指している実体が変わることはありません。
ある意味、@list は構造体へのポインタが並んでいるものと
とらえればいいと思います。

削除の方に関しても同様です。
そして、ある変数の実体をリファレンスによって共用しているとき、
指されている実体の方で複数箇所から参照されているという情報をもっています(リファレンスカウント)。
どこからも指し示されなくなって初めて実体が解放されます。
したがって
>上書きされることはないのでしょうか?
このような心配は無用でしょう。
種類:回答
どんな人:経験者
自信:参考意見
回答日時:08/03/13 15:11
回答番号:No.2
この回答へのお礼御回答ありがとうございました。
リファレンスはアドレスではなく、実体を指し示しているのですね。
よく理解できました。

回答

良回答10pt

回答者:Tacosan 「Perl には明文化された仕様が存在しない」とかいう文章もあったりするので「仕様として正しいか」と言われると困るわけですが, 少なくとも現在の (Perl 5.10.0 までの) 実装としては正しい動作です... というのが質問 1 の答えだと思います.
で質問 2 の方ですが, 「少なくとも 1ヶ所から参照されているデータは削除されない」はずです. つまり, (バグに出会わない限り)「上書きされることはない」というのが答えです.
種類:アドバイス
どんな人:一般人
自信:参考意見
回答日時:08/03/13 14:59
回答番号:No.1
この回答へのお礼御回答ありがとうございました。
 
最新から表示回答順に表示良回答のみ表示