要約: std::move()は「オブジェクト構築/代入操作においてムーブセマンティクス(move semantics)を明示するため」のものであり、それ以外の場面で用いるべきでない。という主張。
FooClass x;
FooClass y{std::move(x)}; // xからyへムーブ操作
FooClass z;
z = std::move(y); // yからzへムーブ操作
不適切事例1
FooClass x;
// std::move戻値を右辺値参照型rxに束縛しておき...
FooClass&& rx = std::move(x);
// あとでrxから"ムーブ"するつもり??
FooClass y = rx;
右辺値参照型の変数 rx をどう利用するつもりでした?あなたの期待に反して FooClass y = rx; は "ムーブ操作" ではなく "コピー操作" になります。rx(つまりx)から "ムーブ操作" を行う場合は、
FooClass y = std::move(rx);
のように、結局は rx に対しても std::move を明示する必要があります。何のために右辺値参照型(FooClass&&)を使ったんでしたっけ?
不適切事例2
FooClass x, y;
// std::move戻値に別オブジェクトを代入??
std::move(x) = y;
このコードで行われる処理は、単純なコピー代入操作(x = y;)と等価です。つまりこのstd::moveは、善良なプログラマを惑わすだけの冗長なシロモノです。やめときましょう。
重箱の隅: コピー代入演算子を operator=(const T&) & と operator=(T&) && でオーバーロード定義すれば、x = y; で前者を std::move(x) = y; で後者をと呼び分けることはできます。ただし(私が知る限り)、後者のセマンティクスについて広く合意されたものはないため、あくまでも自己責任でどうぞ。
やる気の無い解説
-
std::move関数 それ自身は、何の処理も行いません。 -
std::move関数は、型キャスト(type cast) しか行いません。 - 実際の "ムーブ操作" 処理を行うのは、構築/代入対象となるクラス自身です。
- 関数名
moveが示すとおり、「ムーブセマンティクス」をソースコード上で明示するラベル に過ぎません。 - C++文法上は、明示的な型キャストにより "ムーブ操作" を行えます。
std::move関数は必須ではありませんが、分かりやすさのため 利用が強く推奨されます。