Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

C++11 ムーブセマンティクス

C++11 のムーブセマンティクスがよく分からないので実験してみる。

class Bean {
public:
    Bean()
    :color(0)
    ,shape(0)
    {
        std::cout << "constructor\n";
    }
    
    Bean(const Bean& other)
    : color(other.color)
    , shape(other.shape)
    {
        std::cout << "Bean copy constructer\n";
    }

    Bean(Bean&& other) noexcept
    : color(std::exchange(other.color, 0))
    , shape(std::exchange(other.shape, 0))
    {
        std::cout << "Bean move constructer\n";
    }
    
    int color;
    int shape;
};

class Bag {
public:
    Bag()
    {
    }
    std::vector<Bean> beans;
};


int main(int argc, const char * argv[]) {
    printf("1--\n");
    {
        auto bag = Bag();
        Bean bean; // constructor
        bag.beans.push_back(bean); // copy
    }
    printf("2--\n");
    {
        auto bag = Bag();
        Bean bean; // constructer
        bag.beans.emplace_back(bean); // copy
    }
    printf("3--\n");
    {
        auto bag = Bag();
        bag.beans.emplace_back(); // move
    }
    printf("4--\n");
    {
        auto bag = Bag();
        Bean bean; // constructor
        bag.beans.emplace_back(std::move(bean)); // move
    }
    printf("5--\n");
    {
        auto bag = Bag();
        Bean bean; // constructor
        bag.beans.push_back(std::move(bean)); // move
    }
    printf("6--\n");
    {
        auto bag = Bag();
        bag.beans.push_back(Bean()); // constructor + move
    }
    printf("7--\n");
    {
        auto bag = Bag();
        bag.beans.emplace_back(Bean()); // constructor + move
    }
    
    // 1, 2がcopyが走っていて最悪なケース
    // 4, 5, 6, 7 は生成処理が1回、moveが1回
    // 3 は生成処理が1回で最も効率的なケース
    

この例では要素の型が説明のためintになっているが、一般に巨大なクラスだと考えておく。

1--
constructor
copy
2--
constructor
copy
3--
constructor
4--
constructor
move
5--
constructor
move
6--
constructor
move
7--
constructor
move

次にcopy operatorとmove operatorの動作をみてみよう。

    Bean& operator=(const Bean& other)
    {
        std::cout << "Bean copy operator\n";
        if (this != &other) {
            color = other.color;
            shape = other.shape;
        }
        return *this;
    }
    Bean& operator=(Bean&& other) noexcept
    {
        std::cout << "Bean move operator\n";
        if (this != &other) {
            color = other.color;
            shape = other.shape;
        }
        return *this;
    }



    {
        Bean bean1;
        Bean bean2;
        bean2 = bean1;
    }
    printf("--\n");
    {
        Bean bean1;
        Bean bean2;
        bean2 = std::move(bean1);
    }
Bean copy operator
--
Bean move operator

こちらは意図通り、左辺値を渡した時はcopy、右辺値を渡した時はmoveとなった。