19
  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()
4

4 に答える 4

15

イニシャライザが短命の右辺値参照を返す関数呼び出しである場合にのみ問題が発生します。より少ない単語とより多くのコードで:

// 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右辺値参照ではなく値を返すので、問題はありません。

本当の危険は、右辺値参照パラメーターを持つ関数と関数テンプレートにあり、ライフタイムがそれらに依存するいくつかのサブオブジェクトのいずれかへの右辺値参照を返すと私は考えています。(そうは言っても、問題を示すのと同じくらい単純なものauto&& ref = std::move(42);です!)

状況はC++11から完全に新しいものではありません、考慮してください:T const& ref = bar(T_factory());

于 2013-02-13T08:39:47.850 に答える
8
  1. はい。参照型を返さない関数からの戻りには、コピー/移動が含まれる場合があります。それを排除することがRVOの目的です。参照がバインドされているオブジェクトは、何らかの方法で初期化する必要があります。

  2. いいえ、なぜそれが必要ですか?参照にバインドされた一時/prvalueの存続期間は、参照のスコープによって決定されます。

  3. func()が参照型を返さない場合、効率(または動作)に違いはありません。

の間に

auto&& var = func();

auto var = func();

どちらの場合も、包含ブロックの終わりまでの存続期間を持つオブジェクトが作成されます。ある場合にはそれはそれ自身の名前を持ち、他の場合にはそれは参照を介して名前が付けられます。どちらの場合も、名前を左辺値として使用できます。RVOは、どちらの場合でも同様に適切に適用できます。

一部のコンパイラは、参照よりもローカルオブジェクトの方が最適化される場合がありますが、現在の場合、一時への参照は実際にはローカルオブジェクトと同じです。

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

于 2013-02-13T08:43:13.750 に答える
1

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

より単純なケースは次のとおりです。

int foo () {
    return 42;
}

int bar () {
    const int& x = foo();
    return x; // Here is safe to use x
}
于 2013-02-13T08:42:07.633 に答える
0

toの呼び出しを評価した結果は、インスタンス化make_tupleの一時的なprvaluetupleです。auto タイプ指定子は同じtupleインスタンス化(7.1.6.4p6)として推測されるためmytup、タイプはtuple<...> &&です。次に、一時的なprvalueは、参照mytup(12.2p5)によって有効期間が延長されます。

  1. 一時関数の戻り値であるため、コピー/移動は含まれません(RVOがまだ存在する可能性がありますmake_tuple)。
  2. 動作は完全に定義されています。
  3. ほとんどすべての場合、mytupタイプが右辺値参照であっても、は左辺値として扱われます。ただしauto &&、すべての賢明なコンパイラは一時的なものからコピー/移動を排除するため、使用する意味はありません。

mytup明確にするために、右辺値として扱う唯一の方法は、 auto &&が教えてくれるようstd::forward<decltype(mytup)>(mytup)に、を使用することです。; ただし、 (この場合)のタイプがわかっている場合は、を使用することもできます。mytuptuple<...>std::move

于 2013-02-13T08:37:18.257 に答える