2016-12-01 9 views
2

std::moveの次の場合は不要ですか?std :: moveの次のケースは不必要ですか?

std::string member; 

obj(std::initializer_list<std::string> p_list) 
    : member {std::move(join(p_list))} 
{} 

これは、関数への参加である:あなたのjoin機能が正気である、とstd::stringを返し、そう、std::moveは不要だろう考える

std::string join(string_initializer_list p_list) { 
    size_t size {}; 
    for (auto const & s : p_list) { 
     size += s.size(); 
    } 
    std::string output; 
    output.reserve(size); 
    for (auto const & s : p_list) { 
     output.append(s); 
    } 
    return output; 
} 
+0

「結合」とは何ですか? – ildjarn

+0

私は質問を編集しました;) –

+0

どのようなシナリオではstd :: moveは役に立ちますか? –

答えて

4

いいえ、あなたはstd::moveは必要ありません。 std::moveの関数は、任意の値を右辺値にキャストします。あなたの関数は既にrvalueを返しています。したがって、参照に関係する結果を束縛する限りキャストは効果がありません(memberをrvalueから初期化するためのものです)。実際に

std::move積極を使用するコピーの省略を阻害するので、それは厳密pessimizationである:最初の形式、std::string s = join({});

std::string s = join({});    // construct from prvalue, elidable, 
             // elision mandatory in C++17 

std::string s = std::move(join({})); // temporary object must be constructed, 
             // s is initialized by moving from the 
             // temporary 

、コピーの省略は、joinの返されたオブジェクトを直接構築されることを意味しますsの場所(一時オブジェクトが構築されていないか、コピーまたは移動が行われている)、さらには関数本体内の変数outputも省略され、戻り値で直接構成されます。つまり、sです。 std::moveでは、最初の溶出ステップは利用できません。

+0

このケースでは実際にRVOが破損する可能性があります。 – erip

+0

@erip:いいえ、それは別の状況です。関数本体で 'return std :: move(output)'と言った場合です。興味深いことに、そこでの議論は逆のように見える。「出力」は実際には左辺値であるが、特別な魔法の理由から、その状況では実際には正の値として扱われる。 –

+0

ああ、おっと。 :)応答ありがとう!感謝します。 – erip

3

joinからの戻り値はすでにr値です。その向こう

は、/ O std::move wは、コピーの省略はstd::moveを使用すると、その後一時的に破壊し、memberを初期化するために移動コンストラクタを呼び出し、一時的stringを作り、それを強制することができながら、それは、std::moveない場所で結果を構築することができることを意味します。たくさんの作業(ほとんどポインタのコピーはほとんどありません)が必要ですが、それ以上は必要ありません。

+0

私は結合機能を表示するために質問を編集しました;) –

+0

@DagobertoPires:私は自分のステートメントの資格を削除する答えを編集しました。 :-) – ShadowRanger

+0

std :: moveはどのシナリオで役に立つのですか?私はこれについて興味がある。 –

0

明快にするために、値によって返され、したがってrvalueを返す関数は、std :: moveを適用する必要はありません。また、他のものはすでにパフォーマンスの最適化に有害であると指摘しています。

SomeClass fn() 
{ 
... 
} 

// Move not needed, detrimental, as the function result is already an rvalue 
SomeClass x = std::move(fn()); 

ちょうどC++ 11の前にいつものようにこれを行う:一般的に使用STDを話す

SomeClass x = fn(); 

::移動(x)は、xは名前を持っている場合。つまり、それは識別子であり、特別な状況(例えば、コピーエリジョンを防止したい場合を除く)を除いて一時的には役に立ちません。

サイドノート:std :: moveへの移動も試みません(例えば、潜在的な例外に直面して構造体が完全にコピーされたり、そのまま残されている場合など)、移動した型に応じてstd :: moveをスローすることができるため、この型の例外ポリシーはあなたの下で変わる。代わりに、コンパイル時にnoexceptと組み合わされた静的なassertを持つラッパー関数を使用してください。 Is there facility for a strong guaranteed exchange in C++

関連する問題