std::string name;C++98では、=は代入、つまりコピーでした。
name = std::move("hello");
つまり、std::moveだけでは「移動」できる訳がありません。
「移動」するための仕組みは、rvalue参照にあります。
std::moveは、実は実装としては何もしません。
この関数は、rvalue参照の引数を取り、それをrvalue参照に型変換するだけです。
コンパイル時に確認します。
間違えてlvalue参照を渡すと破壊されるので注意が必要です。
実際の「移動」は、rvalue参照を引数にしたstd::string用の=オペレータが処理します。
=オペレータが、rvalueを参照渡しで受け取り、swapして内容を入れ替えます。
std::string&この、引数がrvalue参照の=オペレータを、
operator=(std::string&& str)
{
this->swap(str);
return *this;
}
ムーブ代入オペレータ(move assignment operator)と呼びます。
これまでの引数がconst参照の=オペレータは、
これまで通り代入オペレータ(assignment operator)と呼びます。
しかし、なぜこのムーブ代入オペレータは「移動」するためのswapを使う
コードを記述できたのでしょうか?
それは、rvalue参照渡しのデータは、呼ばれ側が、
自由に壊して良いというルールが存在するからです。
そのため、上記の通りswapを使った、破壊型ですが、
メモリコピーの必要ない高速なコードを書くことができました。
C++11の実装では、std::stringやstd::vectorなど、標準ライブラリ全てに対し、
rvalue参照を取る新しいオペレータや関数を用意して、上記のようにswapを使うなどして、
効率化を向上し、高速化を達成しました。
その結果、std::moveが型変換しかしなくても、「移動」が実現されたというわけです。
これが、moveがsyntaxではなく、semanticsな理由でもあります。
素晴らしい、さあ、窓からC++98を投げ捨(ry
補足: もちろん、std::move("hello")の所も、そのままだとコピーが発生します。
そこで、std::move自体もrvalueの参照渡しで引数を受け取っています。
0 件のコメント:
コメントを投稿