35

私は他のライブラリから多くの関数とメソッドをラップするライブラリを書いています。戻り値の対処を避けるために、私は次のstd::forwardように適用しています:

template<class T>
T&& wrapper(T&& t) { 
   f(t);  // t passed as lvalue  
   return std::forward<T>(t);
}

f返しvoidて取るT&&(または価値をオーバーロードする)。ラッパーは常にラッパーのパラメーターを返し、戻り値では引数の値を保持する必要があります。実際に使用する必要がありstd::forwardますreturnか? RVOはそれを不要にしますか?それが参照 (R または L) であるという事実は、それを不必要にしますか? return が最後の関数ステートメントではない場合 (if 内) は必要ですか?

呼び出し元は arg (参照、R または L) を介して評価された値にアクセスできるため、またはwrapper()を返す必要があるかどうかは議論の余地があります。しかし、私の場合、式で使用できるように値を返す必要があります。voidT&&wrapper()

質問とは無関係かもしれませんが、関数fは から盗まないことが知られているため、 intの最初の使用は不要であり、私によって削除されました。std::forwardf(std::forward<T>(t))

私は小さなテストを書きました: https://gist.github.com/3910503

テストでは、転送されずに返されることTが示されています - -O3 を使用して gcc48 と clang32 に追加のコピーを作成します (RVO は起動しません)。

また、次の UB から悪い動作を取得できませんでした。

auto&& tmp = wrapper(42); 

未定義の動作であるため (UB の場合)、何の原因も証明されません。

4

3 に答える 3

11

tの呼び出し後に がmoved-from 状態にならないことがわかっている場合、fやや賢明な 2 つのオプションは次のとおりです。

  • std::forward<T>(t)typeで戻りT&&ます。これにより、構築は回避されますが、書き込みが可能になります。たとえばauto&& ref = wrapper(42);refダングリング参照が残ります。

  • std::forward<T>(t)パラメーターが右辺値の場合、最悪の場合はムーブ構築を要求するtypeで戻りTます。これにより、上記の prvalues の問題は回避されますが、xvalues から盗まれる可能性があります。

すべての場合において必要ですstd::forwardtは常に参照であるため、コピー省略は考慮されません。

于 2012-10-18T07:19:23.020 に答える
7

この関数に渡される内容によっては、未定義の動作が発生します! より正確には、非左辺値、つまり右辺値をこの関数に渡すと、返された参照によって参照される値は古くなります。

またT&&、「ユニバーサル リファレンス」ではありませんが、効果は またはTとして推定できるという点でユニバーサル リファレンスに多少似ています。問題のあるケースは、次のように推測される場合です。引数は一時的に渡され、関数が戻った後、関数への参照を取得する前に終了します。T&T const&T

の使用はstd::forward<T>(x)、別の関数を呼び出すときにオブジェクトを転送することに限定されています。一時的に入ってきたものは、関数内の左辺値のように見えます。let を使用std::forward<T>(x)するxと、一時的なように見えるためx、呼び出された関数の引数を作成するときに移動できます。

関数からオブジェクトを返す場合、注意が必要なシナリオがいくつかありますが、いずれも関係ありませんstd::forward()

  • 型が実際に参照であるかconstどうかconstに関係なく、オブジェクトで何もせずに参照を返すだけである場合。
  • すべてのreturnステートメントが同じ変数を使用するか、すべてが一時変数を使用している場合、コピー/移動の省略を使用でき、適切なコンパイラで使用されます。ただし、コピー/移動の省略は最適化であるため、必ずしもそうなるとは限りません。
  • 常に同じローカル変数または一時変数が返される場合、移動コンストラクターがあればそこから移動できます。そうでない場合、オブジェクトはコピーされます。
  • 異なる変数が返される場合、または戻り値に式が含まれる場合、参照は返される可能性がありますが、コピー/移動省略は機能せず、一時的でない場合は結果から直接移動することもできません。このような場合std::move()、ローカル オブジェクトからの移動を許可するために使用する必要があります。

これらのケースのほとんどでは、生成された型はであり、ではなくT返す必要があります。ただし、 が左辺値型の場合、結果は左辺値型ではない可能性があり、戻り値の型から参照修飾を削除する必要がある場合があります。シナリオでは、タイプの作品について具体的に尋ねました。TT&&TT

于 2012-10-18T06:34:57.140 に答える
3

std::forwardいいえ、NRVO の最適化を防ぐことができるため、より良い dont return r-value 参照を使用する必要はありません。移動セマンティクスの詳細については、次の記事を参照してください

于 2012-10-18T06:34:53.150 に答える