参照渡しのメリットは?

[上に] [前に] [次に]
初心者 1999/11/13(土) 16:03:17
jcode::convert(\$str,'sjis');
のように参照渡し(?)しなければいけないのは
なぜなのでしょうか。
jcode::convert($str,'sjis');
のように値渡し(?)では問題があるのでしょうか。
こちらの方法だと、
$strの値がコピーされてしまって効率が悪いと言うことでしょうか。
また、以下のようなのが参照渡しなのでしょうか・・?

&hoge(\$hoge);
sub hoge {
  ...
  ${$_[0]} = crypt(${$_[0]}, $abc);
}
print $hoge;

また、
&hoge($hoge);
sub hoge {
  ...
  $_[0] = crypt($_[0], $abc);
}
print $hoge;

でも、同じように動作するのですが、
危険だと聞いたことがあります。
しかし、なぜ危険なのかよくわかりません。
よろしくお願いします。

J.Naka 1999/11/13(土) 19:39:16
 参照渡しでは、関数呼び元の変数そのものが、呼ばれた側の関数内操作をそのまま受けます。元の変数のアドレスを渡している為に、元変数それ自体を操作しているという事になるからです。
 値渡しでは、関数呼び元の変数のコピーを、つまり全く別の変数を渡すため、呼ばれた側の関数内操作は、元変数には及びません。

。。。具体的コード、、、最近参照渡しやってないから、忘れた(^^;

mm 1999/11/13(土) 21:46:03
>$strの値がコピーされてしまって効率が悪いと言うことでしょうか。
そうです。
特に jcode.pl のようなライブラリの場合、引数に巨大なテキストが渡される
可能性もあるので、(コードやメモリなどの)効率のために、「参照渡し」を行います。

>また、以下のようなのが参照渡しなのでしょうか・・?
両方とも perl でいうところの「参照渡し」です。

ただし、前者のコーディングは馬鹿げています。
&hoge(\$hoge);
sub hoge {
  my( $h ) = @_;
  $$h = crypt($$h, $abc);
}
とするのが普通でしょう。

後者は、$_[0] を参照するだけのコーディングなら、たまに見かけますが、
ここに代入するのは、確かに危険かも知れません。
なぜなら、&hoge('abc'); という呼び出しをした場合に、
$_[0] が左辺値にならないからです。

初心者 1999/11/13(土) 22:05:48
J.Nakaさん、mmさん、
わかりやすい説明、ありがとうございました。

>ただし、前者のコーディングは馬鹿げています。
>my( $h ) = @_;
の行がいまいちよくわかりません。
申し訳ありませんが、教えていただけないでしょうか。

mm 1999/11/14(日) 01:55:06
>申し訳ありませんが、教えていただけないでしょうか。
すいません。
なにをお教えすればいいのかが分からないのですが…?

初心者 1999/11/14(日) 01:58:30
すみません。
my( $h ) = @_;の行がなぜ必要なのか
(なぜ${$_[0]}がいけないのか)いまいちよくわからないのですが。

B-Cus 1999/11/14(日) 04:13:27
> my( $h ) = @_;の行がなぜ必要なのか
> (なぜ${$_[0]}がいけないのか)いまいちよくわからないのですが。
引数は @_ というリストに渡される。
$_[0] は @_ の 0番目の要素である。
my ($h) = @_ は、@_ の 0 番目の要素を $h に代入している。
つまり $h は $_[0] と等価である。

よって $_[0] と $h は等価。${$_[0]} と $$h も等価。

つまり、単に読みやすさの問題です。
# とはいえ、$$h と書けるものを ${$_[0]} と書かれたら、
# ソースを読む方はたまらん。

> なぜなら、&hoge('abc'); という呼び出しをした場合に、
> $_[0] が左辺値にならないからです。
ん〜そうかなぁ。
 &hoge(\'abc');
 sub hoge { my ($h)=@_; $$h = crypt($$h, $abc) }
でもエラーになるわけだし、文字列リテラルを渡してよいのかを
管理するのはプログラマの仕事ではないでしょうか。

で、なぜ「危険」なのか理由がよくわからないですが、強いて言うなら
 - &hoge($hoge) で受けるなら、$hoge = &hoge($hoge) と return で返す
 - でなければ、&hoge(\$hoge) で、リファレンスを渡していることを
   わかりやすくする。
てのが一般的な考え方だと思うので、
 - &hoge($hoge) で受けて、$hoge を書き換える
ってのは、わかりにくい書き方だ、ってことで「危険」って言ってるのかな?

mm 1999/11/14(日) 05:34:53
初心者 さん
>(なぜ${$_[0]}がいけないのか)いまいちよくわからないのですが。
いけないという訳ではないです。

ただ、&hoge($hoge) とすれば、$_[0] は既に実引数の $hoge 自身を指し示してますよね。
それなのに、&hoge(\$hoge) として、$hoge のリファレンスを $_[0] で指し示して、
${$_[0]}でデリファレンスすることにより再び $hoge を指し示すようにしてアクセスするのって、
回りくどいと思いませんか?
それなら、&hoge($hoge) として、$_[0] でアクセスする方が早いでしょう。
もちろん、my( $h ) = @_; も、回りくどい方のやり方と同じことをしてる訳ですが、
こちらは、リファレンスの用法に則ったやり方ということで、分かり易いんじゃないか
というだけのことです。


B-Cus さん
>ん〜そうかなぁ。
確かに。
リテラルのリファレンスを渡せることを忘れてました。

>ってのは、わかりにくい書き方だ、ってことで「危険」って言ってるのかな?
これも考えたんですが、Pascalなどの本来の参照渡しでも、呼び出し元では、
参照渡しか値渡しかの区別は付かないんで、これを危険というのもちょっと疑問ですね。

B-Cus 1999/11/14(日) 05:52:10
ふーむ、個人的な結論としては、
 「危険ではない。しかしわかりにくいので、こういう書き方は推奨しない」
ですかね。

> それなら、&hoge($hoge) として、$_[0] でアクセスする方が早いでしょう。
あら、mm さんは &hoge($hoge) で $hoge が書き変わるような書き方は
否定しない、という立場ですか?

mm 1999/11/14(日) 14:03:03
>否定しない、という立場ですか?
いや、その部分は、単に ${$_[0]} は、コードを読んだときに、まわりクドイというだけでの意味です。
実際に書くなら、リファレンスで渡して、my($h)で受けるという立場です(perl4なら型グロブ)。

ただ、「否定しない、という立場か」と言われれば、否定はしないかも知れません。
コードに対してそれほどストイックではないんで、ごくまれですが、$_[0] を使って
書き換えることもありますね(^^;

[上に] [前に] [次に]