質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

3回答

4116閲覧

[C#] outとreturnのどちらが推奨される書き方ですか?

pokudama

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2020/08/04 23:21

outとreturnのどちらが効率がいいのでしょうか?

C#での話です。

以下の2つのコードはメモリ使用に関して、どちらの方が効率(合理的)がいいのでしょうか?

該当のソースコード

C#

1// その1 2List<string> funcA(List<string> strList) 3{ 4 // strListに関する処理。追加したり、削除したり。例えば以下の通り。 5 for(int i = 0; i < strList.Count; i++) 6 { 7 if (strList[i] == "abc") 8 strList[i].RemoveAt(i); 9 } 10 return strList; 11}

C#

1void funcB(ref List<string> strList) 2{ 3 // strListに関する処理。追加したり、削除したり。例えば以下の通り。 4 for(int i = 0; i < strList.Count; i++) 5 { 6 if (strList[i] == "abc") 7 strList[i].RemoveAt(i); 8 } 9 10 return; 11}

メモリに詳しくはないのですが、その1はList<>を新しく作っているような感じで、その2はList<>をそのまま返しているような気がします。
自分としては、「感じで」「気のせいで」というぐらいの知識なので、どうにも自信がありません。
(その2はrefは必要ないかもしれませんが、つまり引数で返すということを示したつもりです。)

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/08/05 02:05 編集

効率はほぼ同じですが、微妙な効率化よりもバグの入りにくいコードが推奨されます。その点で、中身のまずさは別にしても、List を引数にして書き換える副作用を持つこの二つのコードはどちらも良くありません。
fana

2020/08/05 01:19

> その1はList<>を新しく作っているような感じで、その2はList<>をそのまま返しているような気がします。 ここから認識が間違っていると見えます.
kikukiku

2020/08/05 02:50

回答ではありません。 Zuishinさんの意見と同じです。 fanaさんが指摘しているように理解は不十分に思います。 もっと混乱するかもしれませんが、下記を理解できれば良いと思います。 https://ufcpp.net/study/csharp/sp_ref.html その1で戻り値をviodに変更しても、読み出し元では、変化があることに注意。
退会済みユーザー

退会済みユーザー

2020/09/18 00:52

質問者さん、最初の投稿以来無言ですが、多々回答がされていますのでそれらに対するフィードバックを返してください。役に立った/立たなかったぐらいの返事はすぐ返せるはず。役に立たなかったならどこが質問者さんの期待と違うのかも書いていただけるとありがたい。とにかく無言は NG です。マナー的にも。
guest

回答3

0

まず, List<string> とは, 標準のクラスである System.Collections.Generic.List<T> ですよね?
以下はそうであると仮定します.

そのコードは恐らく問題があるので要修正ではあるのですが,
質問の本質はそこでは無さそうなので割愛します.

まず, 結論としてはほぼ変わりません.
以下はその理由になります.

System.Collections.Generic.List<T>class です.
C# には値型と参照型の区別があります.
structenum などの型は値型として, class は参照型として扱われます.

参照型である List クラスの実体 (インスタンス) を作るとします.
作られた List インスタンスは変数に直接結びつけられるのではありません.
List インスタンスがメモリ上のどこかに作られた上で,
作られた List インスタンスがどこにあるのかを示す「参照」という値 (参照の値, 参照値) が作られ,
変数に格納されるのは「参照」なのです.
この「参照」という値はただ場所を示すだけなので, サイズは小さなものです.
数値1つ渡すのと大差ないと考えて下さい.

funcA() のように普通にメソッド引数として渡す場合 (「値渡し」と呼びます) も,
変数に格納される場合と同じく「参照という値」が「値渡し」されます (参照の値渡し).

C#

1funcA(ls); // ls は List<string> インスタンスへの参照. 2 3// 略 4 5List<string> funcA(List<string> strList) // strList に参照値が値渡しされる. 6{ 7 // 略 8 strList.RemoveAt(i); // strList の参照先のインスタンス (= ls と同じもの) を操作. 9 // 略 10}

渡されているのが参照であるため, funcA() 内で strList の参照先を変更しない限り,
結局のところ ls を直接操作するのと変わりません.
なぜなら lsstrList は全く同じインスタンスを参照しているからです.

それに対してメソッド引数に ref, in, out などを付けた場合 (「参照渡し」. 「参照の値渡し」と混同しないよう注意) は,
いわば「変数そのもの」が引数に渡されることになります.

C#

1funcB(ls); 2 3// 略 4 5void funcB(ref List<string> strList) 6{ 7 // 略 8 strList.RemoveAt(i); // strList は ls そのものを指す. 9 // 略 10}

確かに ls の参照を strList へとコピーするためのメモリ消費はあるかも知れませんが,
それは説明した通り数値1つ渡すのと変わらないコストです.
C# の処理系の大きさから考えると全く気にするものではありません.

ref, in, out などを使う場面はもっと別の場面です.

まず out. 引数は渡す前に初期化が必須ではなく, 逆にメソッド内では必ず変更されます.
戻り値以外に何かしらの結果を得たい場合に使う感じですね.

次に in. 引数は渡す前に必ず初期化されている必要があり, メソッド内では変更されません.
class ではほぼ意味がありません. 巨大な struct を渡す場合などに,
コピーせずにそのまま参照するために使われるものと思われます.

そして ref です. 引数は渡す前に初期化されている必要があります.
メソッド内では変更されるかも知れませんし, されないかも知れません.
引数として渡してもらう際に設定されている値を使った上で,
そこに何かしらの変更を加える可能性がある場合に使うということになるでしょう.
...ですが, class の場合は普通の引数でも参照の値渡しなので, 普通に渡せば済みます.

inrefclass であればほとんど意味はありません.
参照であれば, そもそも巨大なコピーは発生しないのですから.
out だけは class であっても使う場面がありますね.

投稿2020/08/05 03:26

kagilinn

総合スコア354

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

outとreturnのどちらが推奨される書き方ですか?

両者を利用する目的が間違っている と思います。

out パラメーター修飾子return ステートメント はそもそも 違う機能 です。
ですから、どちらが推奨なのか比較するのは正しくありません。

メモリ効率を減らすという目的のためにどちらかを選ぶのではなく、それぞれの機能が持つ ** 本来の目的** に応じて使い分けてください。

目的に応じてコーディングを行うことで読みやすいコードができます。
そして、読みやすいコードは一目で動きがイメージできますから、バグが発生しにくいし、直しやすいです。

それを意識した上で、よく考えてください。
より合理的なのは、メモリの効率ではなく 開発の効率 を上げることではないでしょうか。

outとreturnのどちらが効率がいいのでしょうか?

C# のメモリ管理 を学ばれることを強くお勧めします。

それを踏まえて回答すると ** funcA と funcB はインスタンスの生成をしていない** ため、strList やその要素の値が新しくメモリに割り当てられることはありません。(すなわち、メモリの使用率は増加しません)

強いていうならば、for で使われているカウンタ変数 i 分のメモリ (int型なので4byte) が割り当てられるぐらいでしょうか。しかし、ガベージコレクションによって割り当てられたメモリはいずれ解放されます。

また、strList から string 型の要素を削除しています。この処理については、むしろメモリの使用量が減るはずです。

以上のメモリ事情の観点から、funcA と funcB のメモリに関する効率に大差はないでしょう。


そもそもの話、C# でメモリの効率を気にしても仕方がありません。

C# におけるメモリ管理を知ること自体は大切です。しかし、よほどメモリを短時間で大量に割り当てたり解放したりするようなコードを書かなければ大きな問題になることはありません。
ですから、通常のアプリケーション開発では深くまで考慮する必要はありません。

しかし、それ以上にメモリの効率を気にするのであれば、他の言語を検討に入れることも考えてください。

投稿2020/08/05 03:34

編集2020/08/05 04:01
BluOxy

総合スコア2663

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BluOxy

2020/08/05 04:03 編集

また、余談にはなりますが、今回の例題の funcA と funcB の場合、LINQが使えます。 わざわざこれ等のメソッドを定義する必要はありません。 var strList = new List<string>(); var list = funcA(strList); というコードは var strList = new List<string>(); var list = strList.Where(x => x != "abc").ToList(); と書く事ができ、どちらも list には pokudama さんが期待しているであろう結果が返ります。 これも開発効率を上げるための1つの手段です。
guest

0

以下の2つのコードはメモリ使用に関して、どちらの方が効率(合理的)がいいのでしょうか?

メモリ使用の効率化云々の話はどちらも関係ないと思いますけど。

どういう違いがあるかと言うと:

List<string> funcA(List<string> strList)

引数の渡し方は C# のメソッドのデフォルトの値渡し(別の入れ物に中身をコピーして渡す)。

引数の List<string> は参照型なので渡すのはオブジェクト(インスタンス)を指すアドレス情報。値渡しなのでメソッド側で用意した別の入れ物 strList にアドレス情報をコピーして渡している。

つまり、呼び出し元の変数とメソッド側の変数の中身は同じアドレス情報即ち単一のオブジェクトを指している。

なので、メソッド側で変数が指すオブジェクトを変更すると、呼び出し元の変数が指すオブジェクトでも同じ結果となる。return するのは意味がない。

void funcB(ref List<string> strList)

引数の渡し方は参照渡し(入れ物を中身ごと渡す)。

基本は上記と同じだが以下の点が異なる。

呼び出し側の入れ物とメソッドに渡された入れ物 strList は同じになるので、メソッド側で新しくオブジェクト(インスタンス)を生成してそれのアドレス情報を入れ物に代入すると、呼び出し元の入れ物の中身が指すオブジェクトも、メソッド側で生成した新しいオブジェクトになる。

投稿2020/08/05 03:36

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問