トップ

「参照渡し」について

値・変数・代入・別名

プログラミング言語が(広義の)計算の対象とするものを「値」という。たとえば数値と文字列を扱うことができる言語であれば、3.14, 42, "hoge" などのような値がある。

変数

TBD

代入

TBD

別名

TBD

左辺値と右辺値

TBD

仮引数と実引数

TBD

値渡しと参照渡し

一般にプログラミング言語の分野では、

「値結合」「番地結合」の語もある(『JIS FORTRAN 全釈』参照)

$ cat test.cc
#include <cstdio>

void
foo(int x)
{
	x = 2;
}

void
bar(int &x)
{
	x = 2;
}

int
main(void)
{
	int a;

	a = 1;
	printf("%d\n", a);
	foo(a);
	printf("%d\n", a);
	bar(a);
	printf("%d\n", a);

	return 0;
}
$ g++ test.cc
$ ./a.out
1
1
2

C++ での例。foo の x は値渡しなので、callee の foo で x に代入しても caller の a は変化しない。一方 bar の x は参照渡しなので、callee の bar で x に代入すると、caller の a が変化する

これは、変数の値が、たとえば Java でいうプリミティブであるか、オブジェクトの参照であるかということとは関係なく、このように呼ばれる。混乱を緩和しているのか助長しているのか定かではないが、参照の値渡し(pass by value of reference)のような言い方もある( https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope#General に "However, object references are values, too, ..." のような記述がある)

参照渡しがある言語は、C#・C++・VB・PHP・Pascal(変数パラメタ) などわりと珍しく、C・Java・JavaScript・Python をはじめ値渡しのみの言語が専らである。Haskell のように純粋な関数型言語ではプログラマには普通はこの差は見えない

その他名前渡し(名前呼び)とか詳しいことは「プログラミング言語の概念と構造」という本に書いてあって id:nishiohirokazu:20100726:1280161627 にわかりやすいまとめがあるので読まれたい

VB の場合

http://msdn.microsoft.com/ja-jp/ff394162.aspx が VB を使った説明で、非常に詳しい

JavaScript

JavaScript については、mozilla.org のドキュメント https://developer.mozilla.org/ja/Core_JavaScript_1.5_Guide/Functions#簡単な例 に、「オブジェクトへの参照が関数に渡されます。」という表現があるが、これは「参照渡し」である、と言っているのではないことに注意。最新の英語版ドキュメント https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope#General では、

The parameters of a function call are the function's arguments. Arguments are passed to functions by value. If the function changes the value of an argument, this change is not reflected globally or in the calling function. However, object references are values, too, and they are special: if the function changes the referred object's properties, that change is visible outside the function, (以下略)

と、オブジェクトも「値渡し」だと明確に書かれている

実体渡し

pass by reference のことを「実体渡し」と呼んでいる本があるようだが、

「値渡し」「参照渡し」というすでに定訳となっているものに別の用語をあてることになるので宜しくないように思う

dRuby について

dRuby では、分散している Ruby 実行系の間で、引数のオブジェクトをコピー( Marshal.dump / Marshal.load )して渡すことを「値渡し」、DrbObject という「参照オブジェクト」で引数を渡すことを「参照渡し」と呼んでいる

これは、ややこしいが、プログラミング言語の用語とは関係ない、dRuby の用語、と考えた方が混乱しないと思う

.NET では、(参考 http://msdn.microsoft.com/en-us/library/aa720494%28VS.71%29.aspx )分散システムの間での引数の受け渡しを「Marshal」と呼んで表現を区別している。(余談だが Java 以来、受け渡しの概念を含まず単にオブジェクトグラフをバイナリ列で表現することを(Ruby のようにそれも Marshal と言う文化もある)シリアライズと言っているが、複数の操作の直列化を意味するシリアライズと混同するではないか、という意見がある https://groups.google.com/group/fj.comp.oops/browse_thread/thread/e286d606ffec2e93/b0a5482231419a39

PHP について

PHP では、仮引数に & を付けると、参照渡しになる

PHP の考え方では( http://www.php.net/manual/ja/language.references.pass.php を参照)、「リファレンス」というものにより、関数に、変数の中身ではなく変数自体を渡すことにより、仮引数を実引数のエイリアスにする、ということになる。他のプログラミング言語と違い、プログラムが操作する対象として、オブジェクトでなく、変数というものが対象となっていることに注意

実引数に & を付けて(その場合仮引数には & が付いていても付いていなくてもよい。PHP5 で警告の出方が違うので、微妙に細かい挙動が違うようだ)も参照渡しになる。PHP4 以降は、php.ini で allow_call_time_pass_reference = Off の場合(PHP 処理系自体ではデフォルトは On、php.ini のデフォルトは Off)実引数に & を付けると、警告が出る

http://www.php.net/manual/ja/ini.core.php によれば、「PHP5 では allow_call_time_pass_reference は非推奨となります。 PHP 5.3.0 より前のバージョンではこの機能を使うと E_COMPILE_WARNING が発生し、PHP 5.3.0 以降では E_DEPRECATED となります。」となっており「このディレクティブは PHP6 で削除されます。」と書いてあるドキュメントもあるようなので、id:camelmasa:20080626:1214451268 のように(ググったら最初に出てきたというだけで他意はありません)「そんな設定いらないですよ。ホントに…。」とか眠いこと言ってないでとっとと書き直すがいいと思われ

また、PHP5 より前は配列とオブジェクトが、PHP5 では配列が、値渡しすると、たとえば Ruby などとは違い、コピーして(ディープコピーである)渡される。配列の中身を書き換えて返したい場合、参照渡しする必要がある。このことから、Ruby などでの、参照が値渡しされてオブジェクトが共有されているために、オブジェクトの中身を書き換えた結果が呼び出し元に反映することが「参照渡し」と思われることがあるようだが、誤解である

「変数を書き換える」のではなく「オブジェクトの『中身』を書き換える」と書いていることに注意

PHP5 では、オブジェクトの扱いが、他の言語と同じようになった。このことを『ポイントとしてよく言われるのは「オブジェクトはデフォルトでは参照渡しとなります」ということです。しかし、正確には少し異なります。この節では、いくつかの例を用いてその誤解をといていきます』( http://www.php.net/manual/ja/language.oop5.references.php より)というように、PHP5 のドキュメントに「参照渡し」と言われると、そしてそれが誤解であると、書かれている

というか PHP な人にお願いしたいのだけど、ネットで見つかった情報をあてにするんじゃなくて php.net のドキュメントを確認しようよと。そして php.net にリンクを張ってページランク上げようよと