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

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

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

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

2970閲覧

値が参照渡しに自動変換?

reotantan

総合スコア295

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2015/10/21 18:23

下のコードだと参照を渡さないといけないはずなのに、値を渡して、その値が勝手にコードにあうように変更されるとありました。
これはコンパイラーの一機能なのでしょうか?

コード void print(int &parm){ cout<<parm; parm=0; }; void main() { int a=5; print(a); }

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

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

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

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

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

guest

回答3

0

ベストアンサー

質問者さんはこのように思ったのかな?
void print(int *p){}
に実引数を渡す時は
int *p=&a;
print(p);
のようにポインタを渡さなければならない。
void print(int &r){}
の関数は参照指定だから
void print(&a);
のように参照を渡さなければならないと。。。。
ここがポインタと参照の違うところの1つで
参照指定の関数に実引数を渡す時は
print(a);
のように実体をそのまま渡す仕様になっています。
これで関数側では参照として機能します。
ですから、値を渡しているように見えても関数側で参照として処理されます。

私のかってな推測です^^;

投稿2015/10/21 22:57

STL

総合スコア55

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

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

yuba

2015/10/22 00:34

だいたい同じ推測をしました。 これは正直、呼び出し側のコードづらから値渡しなのか参照渡しなのか読み取れないC++の仕様のまずさだとは思っています。例えばref aのように書かないといけないC#のやり方はその点優れていますよね。
reotantan

2015/10/22 07:28

そういう事でしたか、参照の理解が浅かったようです。 ありがとうございました
ipadcaron

2015/10/22 08:22

c++コンパイラの最適化機能、インライン展開のひとつでは? a のライフサイクルとvoid 型の print の戻り値を考慮すれば、最適化による値渡しに変換されるんじゃないでしょうか。値渡しのメソッド呼び出しか、print メソッド自体がインライン展開されて呼び出し自体が無くなると思います。変数a も 0代入後は利用されません。
guest

0

参照渡しが勝手に値渡しになるなんて聞いたことがありません。コンパイルできるように少し書き換えました。

C++

1#include <iostream> 2void print(int &parm) 3{ 4 std::cout << parm << std::endl; 5 parm = 0; 6} 7 8int main() 9{ 10 int a = 5; 11 print(a); 12 std::cout << a << std::endl; 13 return 0; 14}

上を実行すると

5 0

となります。print(a)実行後にaに入った値が書き換わっていますので、きちんと参照渡しになっています。サイトか本かわかりませんが、書いてある情報源はあまり信用しないことをお勧めします。

投稿2015/10/21 22:30

raccy

総合スコア21735

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

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

reotantan

2015/10/22 07:28

なるほど、丁寧な解説ありがとうございました
guest

0

これはコンパイラーの一機能なのでしょうか?

その通りですね。暗黙の型変換です。
例えば、

C++

1char a=5; 2int foo=a;

と書いた場合、「char型変数aの値」が暗黙的に「int型」へ変換されて「int型変数」fooへ設定されます。
同様に、

C++

1int a=5; 2int& param=a;

と書くと「char型変数a」が暗黙的に「char型の参照」へ変換されて「char型の参照」paramへ設定されます。
関数パラメータの時もこれと同じ変換をコンパイラが行っています。

【ところで、ちょっと難しい話ですが、補足です】
参照=(*ポインタ)と考えるとなかなか具合が良いです。

C++

1int a; 2int* p=&a; 3int& q=a;

の時、qと(p)は事実上同じものと言う意味です。
q=10;と
p=10;は同じです。
b=q;とb=*p;も同じです。

そして、参照とポインタの最大の相違は下記です。
例えば、p=&b;とできるのでポインタは他の変数を指すように切り替えることができます。
でも、同じことを参照でやろうと思ってもできません。
文法上、書きようがないからです。q=b;と書いても、(*p)=b;と同義ですから。

さて、「参照」に何を参照しているのか設定しないといけないですが、q=b;では設定できません。
ではどうしましょ?ってことで、初期化時は通常動作できないですから、通常動作とは異なる動作を定義しても問題ないので、初期化時に参照先を設定するように決められたのだと思います。

param=b;は、bの値をparamが参照する変数へ設定しますが、
初期化時のint& param=a;は、aの参照をparamへ直接設定します。
この特殊な振る舞いが一番メジャーな使い方なので、分かり難いのだと思います。

投稿2015/10/22 08:17

Chironian

総合スコア23272

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

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

ipadcaron

2015/10/22 08:52

print メソッドが1個しかなくて、呼び出し箇所も1個なので、引数はそのまま参照渡しでprint メソッドをインライン展開、a のライフサイクルを調査して、a=0 の後で使われないから、a=0 自体を削除、前に戻って、aの参照を見てるとこがなくなったので値渡し。 結局、 std::cout<<5; か、 int a=5; std::cout<<a; になると思われ。 リリースビルドで、最適化オプションを最強にして、アセンブラリストを出力させれば、書籍の言ってる通りになります。
reotantan

2015/10/22 17:36

いや、なかなか難しい内容です、 詳しい解説ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問