C++11でもmove on captureしたい！！！

## 問題提起
C++11で、クロージャを使用する際に、`unique_ptr`をキャプチャしたい、ということもあるのではないでしょうか。
もしかしたら当たり前のことなのかもしれませんが、C++11でそれを達成するための方法を書きました。

こんなコードがあったとします。
hogeクラスは、コンストラクタで受け取った文字列をメンバに持っておき、funcメソッドはその文字列を出力します。
worker::wokerメソッドは引数で受け取ったhogeオブジェクトのfuncメソッドを3秒後に呼び出すスレッドを作成し、
`uniqur_ptr<thread>`を返します。

```cpp
#include <iostream>
#include <memory>
#include <utility>
#include <thread>

using namespace std;

// コンストラクタで渡された文字列を出力するだけのメソッドfuncを持つ
class hoge {
public:
    hoge(string data):_data(data) {};
    void func() {
        cout << "message :" + _data << endl;
    };

private:
    string _data;
};

// workメソッドで渡されたhogeオブジェクトのfuncメソッドを
// 3秒後に呼ぶスレッドを立て、スレッドオブジェクトを返す
class worker {
public:
    worker() {};
    unique_ptr<thread> work(unique_ptr<hoge> hoge) {
        unique_ptr<thread> th(new thread([&hoge]{
            this_thread::sleep_for(chrono::seconds(3));
            hoge->func();
        }));

        return th;
    };
};


int main(int argc, char const* argv[])
{
    unique_ptr<hoge> hoge_ptr(new hoge("hello!!"));
    unique_ptr<worker> worker_ptr(new worker());
    
    // workはthreadオブジェクトを返すのでjoinしてあげる
    unique_ptr<thread> thread_ptr(worker_ptr->work(move(hoge_ptr)));
    thread_ptr->join();
    return 0;
}
```

残念ながら、このプログラムはsegmentation faultエラーを引き起こします。
私の環境での出力は以下のとおりです。

```
$ ./a.out 
zsh: segmentation fault (core dumped)  ./a.out
```

原因はworker::workにあります。

```cpp
unique_ptr<thread> work(unique_ptr<hoge> hoge) {
    // unique_ptr<hoge>型のhogeを参照で受け取っているが、
    // 3秒後にはhogeのデストラクタが呼ばれている
    unique_ptr<thread> th(new thread([&hoge]{
        this_thread::sleep_for(chrono::seconds(3));
        hoge->func();
    }));

    return th;
};
```

参照で受け撮ったhogeが3秒後には生きていないのです。
さて、どうしましょう。

## 解決方法1 C++14を使って move on captureする
C++14で追加された「初期化lambdaキャプチャ」を使います。

スレッドオブジェクトを生成している部分をこのように書き換えましょう。

```cpp
    unique_ptr<thread> th(new thread([hoge = move(hoge)]{
        this_thread::sleep_for(chrono::seconds(3));
        hoge->func();
    }));
```

キャプチャ指定子の中でmoveすればOKです。

## C++11でなんとかする

しかし、何らかの理由でC++14が使えない場合、当たり前ですが初期化lambdaキャプチャを使うことはできません。
そこで、以下のようなクラスを追加します。

```cpp
template<class T>
class move_on_copy {
public:
    move_on_copy(T&& value) : _value(move(value)){};
    move_on_copy(const move_on_copy& other): _value(move(other._value)) {};
    const T& get() const { return _value; };
    T& get() { return _value; };
private:
    mutable T _value;
    move_on_copy& operator=(const move_on_copy<T>& other) = delete;
    move_on_copy& operator=(const move_on_copy<T>&& other) = delete;
};

```
このクラスのインスタンスがコピーされた時、メンバ変数である`_value`はコピー先のインスタンスの`_value`にmoveされます。
`unique_ptr<hoge>`を渡したこのクラスのインスタンスをキャプチャすると、コピーコンストラクタが呼び出され、
無事、クロージャの中で`unique_ptr<hoge>`が使用できるという仕組みです。

この変更を`work`メソッドに適用すると、以下のようになります。

```cpp
unique_ptr<thread> work(unique_ptr<hoge> hoge_ptr) {
    move_on_copy<unique_ptr<hoge>> hoge_container(move(hoge_ptr));
    unique_ptr<thread> th(new thread([hoge_container]{
        this_thread::sleep_for(chrono::seconds(3));
        hoge_container.get()->func();
    }));

    return th;
};
```

実行結果は以下のとおりです。

```
$ ./a.out 
message :hello!!
```

## 参考サイト
この記事を書くにあたり、[Learn how to capture by move](https://marcoarena.wordpress.com/2012/11/01/learn-how-to-capture-by-move/) を参考にしました。