1. はじめに
私はいい歳したC/C++屋さんなのですが、必要に迫られてC#を触っています。そんなこんなで「ん~これはハマりそうだな」と思った事を記録しておきます。自分用メモ。
2.コードその1
実行結果に"1"が表示されるので参照渡しかなぁと思った私。
Program.cs
using System;
using System.Collections.Generic;
namespace ListTest
{
class Program
{
static void Main(string[] args)
{
List<int> testList = new List<int>();
MyFunc(testList);
System.Console.WriteLine(testList[0].ToString());
}
static void MyFunc(List<int> aList)
{
aList.Add(1);
return;
}
}
}
3.指摘を受けました(コードその2)
もし、「参照渡し」なのならばこのプログラムで「2」が表示されるはずなのですが、実際は「1」が表示されます。
Program.cs
static void Main(string[] args)
{
List<int> aList = new ();
aList.Add(1);
MyFunc(aList);
// 結果は"1"が表示される。なぜだ ?
foreach (int x in aList)
{
Console.Write($"{x} ");
}
Console.WriteLine();
}
static void MyFunc(List<int> listA)
{
List<int> listB = new();
// listBに対する超複雑な処理のつもり
listB.Add(2);
// 途中でlistAのデータを見るかもしれないので
// listAは最後まで壊さない
// listAが参照渡しなら結果は2が表示されるはず
listA = listB;
}
こういうことか、と。みんなハマってんだなぁ。
https://qiita.com/yutorisan/items/15e1b6bf21d70770de07
4.では関数引数の中身を壊したくない(値渡しにしたい)場合はどうするか
Program.cs
void MyFunc(List<int> ListA)
{
List<int> ListB = new(ListA);
// ごにょごにょ
}
なのだそうです
5. C++ではどうなるのか
で、C++であればコピーコンストラクタが働きますから「呼び出し元のaListの中身は変わらない」のです。いきなりハマってしまいました。やれやれ。
list5.cpp
#include <iostream>
#include <list>
void MyFunc(std::list<int> list);
int main()
{
std::list<int> aList;
aList.push_back(1);
MyFunc(aList);
// 1 のみ表示される
for (int x : aList) {
std::cout << x;
}
std::cout << std::endl;
}
void MyFunc(std::list<int> worklist)
{
// この時点で aListとは別物
worklist.push_back(2);
}
6. 3の状況をC++で無理やり再現してみた(蛇足)
うわっ。気持ち悪いわ~。
list6.cpp
#include <iostream>
#include <list>
void MyFunc(std::list<int>* pList);
int main()
{
std::list<int> aList;
aList.push_back(1);
MyFunc(&aList);
// 1 のみ表示される
for (int x : aList) {
std::cout << x;
}
std::cout << std::endl;
}
void MyFunc(std::list<int>* pListA)
{
std::list<int> listB;
// listBに対する超複雑な処理のつもり
listB.push_back(2);
// 途中で pListA のデータを見るかもしれないので
// plistA は最後まで壊さない
// なんだこの違和感わ orz
pListA = &listB;
}
コメント頂いた皆様に感謝申し上げます。