26
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

参照型だから参照渡しと安直に呼んでしまう君たちに告ぐ

26
Last updated at Posted at 2024-02-05

いや、気持ちもわかりますが

いや、まぁ 参照型 を関数に 渡す ので 参照渡し と呼んでしまう気持ちはわかります。
ただ、その 参照 型 と 参照 渡し それぞれで使っている 参照 は違う意味だということを忘れないでくださいね。という話です。

C# の用語でも似た話はありまして

C# だって、特に定義されていなかった為 参照変数 というキーワードがありますが、これまでの使い方上、 参照型変数 のことを 参照変数 と呼んでいる場合がままよくあり(1, 2)、その関係か ref ローカルローカル参照変数 などと別の名前で呼ばれたりもします。(翻訳上安定しないもある可能性があるが

参照渡しの誤ったサンプル例

で、参照渡し ですが、よくあるコードの説明だと次の様に値渡しであることを誤って参照渡しの説明がされることがあります。

using System;

var c = new Class(1);
// 参照渡し
Call(c);

// c.V が 1 から 2 に変更される
Console.WriteLine(c.V);

void Call(Class c)
{
  c.V = 2;
}
class Class(int v) {
  public int V {get; set;} = v;
}

SharpLab

これはテストの仕方が誤りです。これは同じインスタンス(参照型でいうところの参照)が使われているという証明にしかならないです。(いわゆる 共有渡しとか言われるそれです。)

参照渡しの正しいサンプル例

やるなら次の様にインスタンスを比較するべきです。

using System;

var c = new Class(1);
var cOld = c;
Call(ref c);

// c が cOld と違うインスタンスに 変更される
Console.WriteLine(cOld != c);

void Call(ref Class c)
{
  c = new Class(2);
}
class Class(int v) {
  public int V {get; set;} = v;
}

SharpLab

これで 参照渡し により 変数c (参照渡しに於ける参照の先) が上書きされていることがわかります。

参照型の代入を参照渡しと呼んでいる君たちに告ぐ

また、値渡しの例から 代入 を参照渡しと呼んでいる例を多く見もします。(本来は関数の引数の話なのでその呼び方は誤りです。

using System;

var c = new Class(1);

// 参照渡し
var c2 = c;
c2.V = 2;

// c.V が 1 から 2 に変更される
Console.WriteLine(c.V);

class Class(int v) {
  public int V {get; set;} = v;
}

SharpLab

これも先述の 値渡しを 参照渡しと誤って呼んでいるパターンと同じで 同じインスタンスを使っているので……敢えて言うならば前述の通り、共有渡しとか呼ばれたりするそれの類です。(私自身は参照の値渡しよりは値渡しと呼ぶ派閥です。

参照渡し で言う 参照 で書くなら次の様に書けます。

using System;

var c = new Class(1);

// 元のインスタンスを退避
var cOld = c;

// 参照変数
ref var c2 = ref c;
c2 = new(2);

// c が cOld と違うインスタンスに 変更される
Console.WriteLine(c != cOld);

class Class(int v) {
  public int V {get; set;} = v;
}

SharpLab

この ref のつく代入は コメントの通り、先述していた C# に於ける 参照変数 とか refローカル とか ローカル参照変数 とか呼ばれたりするアレです。

もうひとつよくある 参照渡し の説明誤りパターン

先ほどまでのコードは class を使って 参照渡しを表現するコードばかりではありましたが、よくあるコードとして 配列を使った 誤りコードをよく見ます。

例えば、次の様なコードです。

using System;

int[] a = [1,2,3];

// 参照渡し
Call(a);

// a[0] が 1 → 2 に変更される
Console.WriteLine(a[0]);

void Call(int[] a)
{
  a[0] = 2;
}

SharpLab

これも同様の勘違いなのですが、 そもそも C# の配列の インデクサは は参照戻り値なので次の様に書けば参照渡しのいい例になります。

using System;

int[] a = [1,2,3];

// 参照渡し
Call(ref a[0]);

// a[0] が 1 → 2 に変更される
Console.WriteLine(a[0]);

void Call(ref int n)
{
  n = 2;
}

SharpLab

結論

参照渡し の説明には 参照型 の説明は不要です。
文字列は 値型の様な挙動をし みたいな説明も不要なんです。(こっちは参照型というよりもミュータブル/イミュータブルの違いなので別)

以上。

26
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?