Boost 1.48.0で入ってからBoost.Moveを使ったことがなかったのと、そろそろ使いそうなので検証してみます。
まず、左辺値のムーブ。
#include <iostream> #include <boost/move/move.hpp> class X { int value_; bool is_destroyed_; private: BOOST_MOVABLE_BUT_NOT_COPYABLE(X) public: X(int value) : value_(value), is_destroyed_(false) {} ~X() { std::cout << "dtor value:" << value_ << " is_destroyed:" << std::boolalpha << is_destroyed_ << std::endl; } X(BOOST_RV_REF(X) x) { x.is_destroyed_ = true; // 所有権の移譲っぽいこと value_ = x.value_; std::cout << "move ctor" << std::endl; } }; int main() { X x1(3); { X x2 = boost::move(x1); } }
move ctor dtor value:3 is_destroyed:false dtor value:3 is_destroyed:true
boost::move()に左辺値を渡してからコンストラクタを呼び出すことで、ムーブコンストラクタが呼ばれていますね。
C++03環境の場合、boost::move()ではboost::mvという型にオブジェクトを変換します。BOOST_MOVABLE_BUT_NOT_COPYABLEのようないくつかあるマクロのどれかを使用すると、そのクラスのオブジェクトをboost::mvに変換するための演算子が定義されます。コンストラクタや演算子のオーバーロードで使用しているBOOST_RV_REFはboost::mv型になります。move対象かどうかで型が違うのでオーバーロードできます。
次に右辺値のムーブ。先ほどのプログラムのmain()関数を、ちょっと書き換えます。
#include <iostream> #include <boost/move/move.hpp> class X { int value_; bool is_destroyed_; private: BOOST_MOVABLE_BUT_NOT_COPYABLE(X) public: X(int value) : value_(value), is_destroyed_(false) {} ~X() { std::cout << "dtor value:" << value_ << " is_destroyed:" << std::boolalpha << is_destroyed_ << std::endl; } X(BOOST_RV_REF(X) x) { x.is_destroyed_ = true; // 所有権の移譲っぽいこと value_ = x.value_; std::cout << "move ctor" << std::endl; } }; int main() { X x2 = X(3); }
move ctor dtor value:3 is_destroyed:true dtor value:3 is_destroyed:false
右辺値の場合、boost::move()を通さなくてもムーブコンストラクタがちゃんと呼ばれていますね。