合計 昨日 今日

c++11 const参照の受け方について

[このトピックは解決済みです]

フォーラムルール
フォーラムルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Name: takashi
[URL]
ぴよぴよ(185 ポイント)
Date: 2017年9月07日(木) 01:29
No: 1
(OFFLINE)

 c++11 const参照の受け方について

c++でわからないことがあるので質問させてください。

ある関数があって、例えば

class Bar {
const std::vector<std::shared_ptr<hoge>& fuga();
}
のようなconst参照を返す関数があったとします。

このとき、この受け方なのですが、
実際にはRVOなどを考えるとそもそもconst参照で返す必要がないのかもしれないのですが、
(これについてもご意見を伺いたいです。)

もしこのような関数があったとき、受ける側は、

auto fuga = bar.fuga();

で受けるのか、

const auto& fuga = bar.fuga();

で受けるのとではどちらが良いでしょうか?

また、前者の場合は、fuga()がcons参照で返しているので、
そもそもauto fuga = bar.fuga();で受けた場合もconst auto fuga& = bat.fuga()
で受けた場合もまったく同じになりますでしょうか?
前者で受けた場合もconst参照になるのかが知りたいです。

また、c++では関数の返り値がconst参照でなかった場合
つまり
class Bar {
std::vector<std::shared_ptr<hoge>> fuga();
}
だった場合でも、
受ける側がconst auto& fuga = bar.fuga();だった場合はfuga()はコピーではなくてconst参照で返すのでしょうか?
(こちらもRVOを考えるとそもそもコピーは作られないのかもしれないですが、最適化は無効にしているとしたらどうなるでしょう)

以上の3点が知りたいです。よろしくお願いします。

Name: tk-xleader
[URL]
プログラマー(34,573 ポイント)
Date: 2017年9月07日(木) 14:49
No: 2
(OFFLINE)

 Re: c++11 const参照の受け方について

(1) 戻り値の受け取り方はケースバイケースで異なります。受け取った後でその変数を変更するつもりなら単にautoで受け取ることになります。戻り値を読み取りに使うだけなら余分な初期化が生じないconst&で受け取る方がいいでしょう。
(2) 単にautoと記述した場合には、テンプレート関数の引数推論と同じ規則で型が決定されるので、初期化値の型がconst&であっても変数がconst&修飾されることはないです。
(3) 戻り値が参照ではないのであれば、最適化を無視すれば戻り値のために一時オブジェクトが生成されます。したがってbar.fuga()は一時オブジェクトを生成してそれを返し、戻り値の一時オブジェクトをconst&で参照しているというコードになります。

Name: takashi
[URL]
ぴよぴよ(185 ポイント)
Date: 2017年9月08日(金) 01:25
No: 3
(OFFLINE)

 Re: c++11 const参照の受け方について

返信ありがどうございます。
非常に参考になりました。

コピーコストを嫌がってconst参照で返しているなら、
受ける側もconst参照にした方が良さそうですね。

(1)で質問があります。
dectype(auto)ではなく(今回はC++11なのでそもそも使えないが)、
単にautoとして受けた場合、参照は外れてしまうみたいですが、
この場合は変数を変更できるということは、
const参照で返しても参照だけでなく、constも外れてしまうということでしょうか?
(3)は一時オブジェクトを参照で延命させているだけで、
一時オブジェクト自体の生成コストがかかってしまうのですね。

また、一般的にはコンパイラの最適化を期待して、
高速化のためだけだったら特にconst参照で返さないで、
コピーで返すのが普通なのでしょうか?

よろしくお願いします。

Name: tk-xleader
[URL]
プログラマー(34,573 ポイント)
Date: 2017年9月09日(土) 21:48
No: 4
(OFFLINE)

 Re: c++11 const参照の受け方について

単にautoで変数を宣言すると、テンプレート関数の引数型と同じ規則によって変数型が決まります。例えば、
コード[C++]: 全て選択
1
template<typename T>void f(T arg){}
にint const&な値を渡した場合、argの型はconstも参照も外れた単なるint型になります。それと同じで、
コード[C++]: 全て選択
1
auto val = f();//const hoge& f();
とすると、変数valの型は単なるhogeになります。

関数の戻り値をconst&にするかどうかはケースバイケースなのですが、const&を返す場合は、関数内で寿命が尽きるオブジェクトを戻り値にしないように注意しなければいけないので、戻り値にできるのはグローバル変数、static変数あるいはクラスのメンバ変数くらいに限られます。

Name: takashi
[URL]
ぴよぴよ(185 ポイント)
Date: 2017年9月10日(日) 12:43
No: 5
(OFFLINE)

 Re: c++11 const参照の受け方について

[解決!]

ありがとうございます。理解しました。
テンプレートについてはまだまだ浅い知識しかないので、
次はその辺りを勉強しようと思います。
ありがとうございました。


Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[19人]