2013-02-13 4 views
17
auto&& mytup = std::make_tuple(9,1,"hello"); 
    std::get<0>(mytup) = 42; 
    cout << std::get<0>(mytup) << endl; 
  1. コピーは make_tupleからの復帰時(RVOなし)関与を移動/ありますか?
  2. 未定義の動作が発生していますか?
  3. 私は両方とも汎用参照を書くことができます。コピー/移動がないようにauto var = func()の代わりにauto&& var = func()を常に使用できますか?
+0

参照は参考資料です。 –

+0

について 'auto && var = func()'、http://stackoverflow.com/questions/13618506/is-it-possible-to-stdmove-objects-out-of-functions-c11/13618587#13618587 – billz

+3

@billzリンクは、ローカル変数を参照として返す別のケースです。バグは、呼び出されていない関数の中にあります。 – balki

答えて

7
  1. はい。参照型を返さない関数からの戻りは、コピー/移動を伴います。それを排除するのは、RVOのことです。参照がバインドされているオブジェクトは、何とか初期化する必要があります。

  2. いいえ、どうしてですか?参照にバインドされた一時的な値/一時的な値の存続期間は、参照の範囲によって決まります。

  3. FUNC()が参照型を返さない場合、効率(でも動作)に差があってはならない

auto&& var = func(); 

auto var = func(); 

どちらの場合も、包含ブロックの終端までの有効期間を持つオブジェクトが構築されます。あるケースでは独自の名前を持ち、もう1つのケースでは参照によって名前が付けられます。どちらの場合も、名前は左辺値として使用できます。いずれの場合でもRVOを同様に良好に適用することができる。

コンパイラの中には、現在のケースでは一時参照が実際にローカルオブジェクトと異なるものではなくても、ローカルオブジェクトに対して参照よりも最適化を行うものがあります。

func()が参照を返す可能性がある場合は、状況が大きく異なります。その場合は、コピー/移動するかどうかを決定する必要があります。

+0

funcが 'Foo&func()'のような左辺値を返すと、 'auto'がコピーする間に' auto && 'バージョンはコピーされません。 – balki

+0

@balki:しかしここでは値を返す関数について議論していました。私は今この区別を明確にしました。 – JoergB

+0

"参照にバインドされた一時的な/ prvalueの有効期間は、参照の範囲によって決まります。"これはC++ 11の新機能ですか? c + 03では、これはconst参照の場合にのみ当てはまりました。 – Suma

0

make_tupleへの呼び出しを評価した結果は、tupleインスタンシエーションの仮の一時的な値です。 auto型指定子は同じtupleインスタンス化(7.1.6.4p6)と推定されるため、mytuptuple<...> &&です。次に、仮価値の一時価値は、参照mytup(12.2p5)によって生涯延長されます。

  1. 一時的関数の戻り値で、何のコピーが存在しないので/関与移動(まだmake_tuple内RVOがあるかもしれません)。
  2. 動作は完全に定義されています。
  3. ほとんどの場合、mytupは、型がrvalue参照であっても左辺値として扱われます。しかし、すべての分かりやすいコンパイラが一時的なコピー/移動を削除するので、auto &&を使用している点はありません。右辺値がWhat does auto&& tell us?のように、std::forward<decltype(mytup)>(mytup)を使用することであるとしてmytupを扱われているための唯一の方法については、明確にするために

。しかし、あなたがを知っている場合mytup(この場合はtuple<...>)のタイプを知っている場合はstd::moveを使用することもできます。

14

初期化子が短命のrvalue参照を返す関数呼び出しである場合にのみ問題があります。少ない単語とコードで:

// Fine; lifetime extension applies! 
auto&& ref = 42; 

auto id = [](int&& i) -> int&& { return std::move(i); }; 
auto&& uhoh = id(42); 
// uhoh is now a stale reference; can't touch it! 

対照的に、auto uhoh = id(42);は正常に機能していました。

std::make_tupleは値を返しますが、r値の参照ではないため、問題はありません。

実際の危険は、rvalue参照パラメータを持つこれらの関数と関数テンプレートから来ており、生存時間がそれらに依存するいくつかのサブオブジェクトのいずれかにrvalue参照を返していると私は考えています。 (言われているように、auto&& ref = std::move(42);のような単純なものが問題を呈しています!)

状況は全く新しいC++ 11ではなく、以下を考慮してください:T const& ref = bar(T_factory());

+4

+1、私は 'T const&pass(T const&t){return t; } '一時的な参照を返すClangの検出を改善しようとしたときの例...可能な*問題を検出するために手続き間の分析が必要であることは残念です:x –

0

一時的に参照をバインドすると、一時的な有効期間が参照の有効期間まで延長されるというC++(C++ 11以前の場合もある)には特定の規則があります。

単純な場合は、次のとおりです。

int foo() { 
    return 42; 
} 

int bar() { 
    const int& x = foo(); 
    return x; // Here is safe to use x 
} 
+2

ルールはconst参照のみです。私はそれが自明ではないと思う&&はconstリファレンスです - それは? – Suma

+0

@Suma:参照は、コンパイラのバックエンドの参照です。 Const-correctnessは、フロントエンド(正当なものとそうでないもの)にのみ影響し、未定義の動作やパフォーマンスに関して何の役割も果たしません。 – 6502

+0

私は間違っているようです。標準のconstについては何も見ることができません。対応する文章は、少なくともC++ 11のドラフトでは、「参照が一時的にバインドされているとき」と書かれています。チュートリアルではconst&について語っていますが、これは恐らくplain&がとにかく一時的に束縛されないからです。 – Suma

関連する問題