要約: 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
関数は必須ではありませんが、分かりやすさのため 利用が強く推奨されます。