CPPの右辺値参照・ムーブセマンティクス〜その3〜

前回の投稿で「ムーブ」の意味があやふやなままになってしまったので、ここで探ってみる。スマートポインタを使うが、それについては深く触れない。

struct hoge {
    std::shared_ptr<int> ptr;
    hoge(int val):ptr(new int(val)) {};
    int getCount() { return ptr.use_count(); }
    void release() { ptr.reset(); }
};

という状況で、

hoge Hoge1(1);
hoge Hoge2(Hoge1);
hoge Hoge3(Hoge2);

std::cout << Hoge3.getCount() << std::endl;    // => 3
    
Hoge2.release();

std::cout << Hoge3.getCount() << std::endl;    // => 2

となるが、一方で、

hoge Hoge1(1);
hoge Hoge2(std::move(Hoge1));
hoge Hoge3(Hoge2);

std::cout << Hoge3.getCount() << std::endl;    // => 2
    
Hoge2.release();

std::cout << Hoge3.getCount() << std::endl;    // => 1

となる。move関数によって、ポインタの所有権が渡されている(ムーブ)。このとき、オブジェクトのコピーは行われていないので、効率が良いという利点がある。ただし、一度所有権を渡すと、そのあとにオブジェクトを参照したり、deleteしたりしてはいけない。

unique_ptrにおいては、

struct hoge {
    std::unique_ptr<int> ptr;
    hoge(int val):ptr(new int(val)) {};
    void release() { ptr.release(); }
};

という状況で、

hoge Hoge1(1);
hoge Hoge2(Hoge1);

とすると、

error: call to implicitly-deleted copy constructor of 'hoge'
    hoge Hoge2(Hoge1);

というエラーが出る。これは、unique_ptrは所有者が一人だけでないといけないため、コピーして所有者を増やすことができないために起きる。(それを実現するためにコピーコンストラクタを消している?)一方、

hoge Hoge1(1);
hoge Hoge2(std::move(Hoge1));

としても、エラーは出ない。これは、所有者を移しているだけなので、所有者は一人のままだからだ。これもムーブコンストラクタをうまく定義することで実現している?