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::move
。TestMove::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 つのケースです)。