代入は、実質的にはオブジェクトのコピーである・・・。
obj = func(); // funcは右辺値なので一時オブジェクトをobjにコピーすることになる.
例えば、上のような場合にobjやfunc()の戻り値がint型ならまだしも、これが大きなクラスオブジェクトのコピーとなると、コピーコストも大きい・・・。
しかも、func()は右辺値であり、一時オブジェクトであるから、コピー後は不要・・・。いずれ破棄される存在・・・。コピーをすること自体無駄に思える・・・。
このように、一時オブジェクトの内容を別のオブジェクトに渡したい場合は、コピーではなく、所有権を移動する形(ムーヴ)にすればコピーコストも発生しない・・・。
C++11のutilityヘッダにあるstd::moveを使うと、あるオブジェクトから別のオブジェクトに内容をムーヴできる・・・。
右辺値参照・ムーブセマンティクス - cpprefjp C++日本語リファレンス
move (utility) - cpprefjp C++日本語リファレンス
std::moveは右辺値だけでなく、左辺値にも適用できる・・・。
今回は変数やオブジェクトなどの左辺値に対して、std::moveを使って別の変数やオブジェクトに所有権を移動する・・・。
するとどうなるか・・・。
int型のval、std::stringのstr、int型std::vectorのvec_iを宣言・・・。
val, str, vec_iに適当に値を代入したり、追加したりしてみる・・・。
いったん出力・・・。
vec_iは値だけでなくsizeも・・・。
std::moveにval, str, vec_iを渡して、戻り値をnew_val, new_str, new_vec_iとして、これらに所有権を移動する・・・。
すでに所有権のない無効なval, str, vec_iと新しい所有者new_val, new_str, new_vec_iの内容を出力・・・。
最後に、val, str, vec_iをいじってみる・・・。
実行すると、
$ g++ move.cpp -o move -std=c++11 $ ./move val = 10 str = ABCDE vec_i = 1, 2, 3 vec_i.size() = 3 val = 10 str = vec_i.size() = 0 new_val = 10 new_str = ABCDE new_vec_i = 1, 2, 3 new_vec_i.size() = 3 val = 20 new_val = 10 str = XYZ new_str = ABCDE vec_i[0] = 10 vec_i.size() = 1 new_vec_i = 1, 2, 3 new_vec_i.size() = 3 $
new_val, new_str, new_vec_iの方に内容が移動しているようにみえる・・・。
valの10は残っているように見えるけど、これはたまたままだ参照できているだけ・・・。
明け渡した以上、val, str, vec_iとnew_val, new_str, new_vec_iは独立している・・・。
所有権を明け渡したあとのオブジェクトに適当に値を入れたりしてみる・・・。
独立してるから、val, str, vec_iの値にnew_val, new_str, new_vec_iが引っ張られることは無い・・・。
いちおう、動くけど、実際は所有権を明け渡した後のオブジェクトの動作は未定義だか不明だか・・・。まあ、本来はやらないほうがいい・・・。
Sample/cpp/utility_move/utility_move/src/utility_move at master · bg1bgst333/Sample · GitHub