常に `sink` コンストラクターまたはセッター引数で移動する必要がありますか? 質問する

常に `sink` コンストラクターまたはセッター引数で移動する必要がありますか? 質問する
struct TestConstRef {
    std::string str;
    Test(const std::string& mStr) : str{mStr} { }
};

struct TestMove {
    std::string str;
    Test(std::string mStr) : str{std::move(mStr)} { }
};

GoingNative 2013を見て、私はシンク引数は常に値渡しされ、 で移動される必要がありますstd::moveTestMove::ctorこの慣用句を適用する正しい方法ですか? の方がTestConstRef::ctor良い/より効率的なケースはありますか?


単純なセッターについてはどうでしょうか? 次の慣用句を使用するか、 を渡す必要がありますかconst std::string&?

struct TestSetter {
    std::string str;
    void setStr(std::string mStr) { str = std::move(str); }
};

ベストアンサー1

簡単な答えは「はい」です。


理由も非常に単純です。値で保存する場合は、移動 (一時から) またはコピー (左辺値から) のいずれかが必要になる可能性があります。両方の状況で、両方の方法で何が起こるかを調べてみましょう。

一時的な

  • 引数を const-ref で取ると、一時変数は const-ref にバインドされ、再度移動することができなくなるため、(役に立たない) コピーが作成されてしまいます。
  • 引数を値で受け取る場合、値は一時的(移動)から初期化され、その後、自分自身が引数から移動するため、コピーは作成されません。

1 つの制限: 効率的な移動コンストラクターのないクラス (などstd::array<T, N>) では、1 つのコピーではなく 2 つのコピーが実行されるためです。

l値から(または const temporary ですが、誰がそんなことをするでしょうか...)

  • 引数を const-ref で取得すると、何も起こらず、その後にそれをコピーします (そこから移動することはできません)。したがって、単一のコピーが作成されます。
  • 引数を値で受け取る場合は、引数にそれをコピーしてからそこから移動するため、単一のコピーが作成されます。

1 つの制限: 移動がコピーに似ている同じクラス。

したがって、簡単な答えは、ほとんどの場合、シンクを使用することで不要なコピーを回避できる(移動に置き換える)ということです。

唯一の制限は、移動コンストラクタがコピーコンストラクタと同じくらい高価 (またはほぼ同じくらい高価) なクラスです。この場合、1 つのコピーではなく 2 つの移動を持つことが「最悪」です。ありがたいことに、そのようなクラスはまれです (配列は 1 つのケースです)。

おすすめ記事