読者です 読者をやめる 読者になる 読者になる

Boost.Moveの検証

C++

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()を通さなくてもムーブコンストラクタがちゃんと呼ばれていますね。