参照渡しとポインタ渡し
解決したいこと
大学の講義でC++の参照渡しとポインタ渡しについて学んだのですが、ポインタ渡しの使いどころがわかりません。
ネットなどで調べたのですが、どちらも共通している部分が多いどころか、参照渡しの方が優れているように思えます。
あえてポインタ渡しを使う場面はあるのでしょうか?また、ポインタ渡しを使うメリットはあるのでしょうか?
大学の講義でC++の参照渡しとポインタ渡しについて学んだのですが、ポインタ渡しの使いどころがわかりません。
ネットなどで調べたのですが、どちらも共通している部分が多いどころか、参照渡しの方が優れているように思えます。
あえてポインタ渡しを使う場面はあるのでしょうか?また、ポインタ渡しを使うメリットはあるのでしょうか?
歴史的経緯があって事情は複雑です。 言語機能の根本にあるので様々な機能と絡み合っています。 ポインタだけに着目した本も出ていて、きちんとした説明をしようとすれば本一冊分くらいにはなるということです。 端的には説明できません。
強いて明瞭な違いを挙げるとしたら、参照はオブジェクトではない (値としてやりとりできない) ということに対してポインタはポインタ型のオブジェクト (いわゆるファーストクラスオブジェクト) であるということが挙げられます。
オブジェクトとしてやり取りできるポインタのほうが自由度は高いです。 その一方で、自由に使えるということは間違った使い方も引き起こしやすいので不必要なら避けるに越したこともありません。 参照で足りるときなら参照のほうが優れているというのは間違いではないと言えます。 しかし参照では出来ないことがあるということです。
その先生に質問してはどうでしょう?
参照渡しの方が優れているように思えます。
何故そう思うのですか? あなたなりにそう思う理由を書きませんか。
【追記】
質問者さんはどの回答に対しても一切フィードバックを返さず去ってしまったようですが、自分の回答が上のまま何の議論もなく終わってしまっては何なので、以下追記しておきます。
質問者さんの言う「参照渡し」と「ポインタ渡し」は以下の関数の例で、それぞれ 2 つ目、3 つ目の仮引数のことを言っているのだと理解してます。(ちなみに 1 つ目は値渡し)
void f(int val, int& ref, int* ptr)
{
// 処理
}
どれが適しているかは適材適所のはずです。当たり前の話ですが「参照渡しの方が優れている」のは参照渡しを使う場所が他に比べてより適所の場合です。
参照渡しが適所でない例として、以下のような場合、
void incr(int& aa) { aa++; }
void f()
{
int x = 1;
incr(x);
}
incr が呼び出されると、その引数 aa は x の別名となります。プログラムを読みやすく保つために、実引数の値を変更する上記のような関数は避けるのがよさそうです。
以下のように、関数の戻り値として結果を返したりポインタ引数を渡す方が望ましいと思います。
int next(int p) { return p + 1; }
void inc(int* p) { (*p)++: }
void g()
{
int x = 1;
x = next(x);
inc(&x);
}
他の例としては、以下のような文字列をコピーする関数の場合、ポインタ渡しが適材適所の適所と思います。
void strcpy(char* s, char* t)
{
while(*s++ = *t++)
;
}
色々場面はあると思いますが、一つは、結果を返すために使います。
void func(int a, int b, int* c, int* d) {
*c = a / b;
*d = a % b;
}
int c, d;
func(123, 7, &c, &d);
//c : 17
//d : 4
closeのレスですみません。
参照渡しの方が優れているように思えます。
五十歩百歩です。ただ、用いるだけです。
関数の引数で用いられる概念として説明
つまり、ポインタを操作する側が異なるだけで、親側で操作する参照渡しの方が安全な共有方法です。しかし、親側の範囲を超えて自由に操作できるポインタ渡しは参照渡しにできない曲芸ができます。
「クローズ」ってなってても書けるのかな?(っていうのを試してみる→可能だとしたら「クローズ」とは何なのか?)
「参照は 必ず構築済みのオブジェクトを参照しなくちゃならない」とか言えばちょっとは「使いづらそう」とか思えるのでは.
分かりやすい話としては,ポインタには「ヌルポインタ」というのがある.参照には無い.
//こういう書き方が 良い/好ましい/etc か否かみたいな話は別として,
//ポインタならこういう話ができるよね.
//
//処理結果は戻り値で返す.
//加えて,引数がヌルポインタでない場合には,
//処理中に得られる何らかの(呼出側にとって有益なことがある)情報を引数が指す先に格納する.
//この情報を受け取る必要が無い場合にはヌルポインタを指定してよい.
MainResult SomeFunc( SubInfo *pDstSubInfo );