自作クラスをムーブする

ユーザー定義のクラスに[move constructor](http://en.cppreference.com/w/cpp/language/move_constructor)を追加するための方法についてまとめます。
既存の型に`std::move`使うと便利なので、自作の型に対しても定義したい、という方向けです。

先に結論をまとめておくと、注意するべきは以下の3点です：

- ユーザー定義のコピーコンストラクタやデストラクタがあるとデフォルトのムーブコンストラクタは作られない
- ムーブされた残り滓`a = std::move(b)`の`b`のデストラクタは呼ばれる
- noexcept付けないとムーブの恩恵が得られなくなる場合がある

ムーブコンストラクタはいつ勝手に作られるの？
------------------------------------------

`unique_ptr`や`vector`の様な既存の型を複数個組合せた構造体

```cpp
struct MyStruct{
  std::unique_ptr<MyStruct> p;
  std::vector<int> v;
};
```

において期待されるムーブコンストラクタは、
個々の要素`p`, `v`のムーブコンストラクタをそれぞれ呼び出すようなものでしょう。
以下の5つの条件を満す場合、デフォルトのムーブコンストラクタがimplicitに定義されます。

- ユーザー定義コピーコンストラクタが無い
- ユーザー定義コピー代入演算子が無い
- ユーザー定義ムーブ代入演算子が無い
- ユーザー定義デストラクタがない
- (until C++14) 以下に説明する条件によってムーブコンストラクタがdeleted指定になっていない

ただし`T(T&&) = default;`で強制的にデフォルトのムーブコンストラクタを定義させる事ができます。

```cpp
struct A{
  A(){}
  ~A(){}             // 自作デストラクタがあるので
                     // デフォルトのムーブコンストラクタの生成が阻害される
  A(A&&) = default;  // これでデフォルトのムーブコンストラクタが定義される
};
```

以下の場合にはデフォルトのムーブコンストラクタがdeleted指定されます

- ムーブできない非静的データメンバーがある
- ムーブできないクラスのインスタンスを含んでいる
- デストラクタが無いかアクセスできないクラスのインスタンスを含んでいる
- 共用体であり、非自明なコピーコンストラクタを持つ[variant member](http://stackoverflow.com/questions/11525964/what-is-variant-member-in-c)を持つ場合
- (until C++14) ムーブコンストラクタが無く、自明なコピーができない(not trivially copyable)非静的メンバーがある

### 参考HP
- [Move constructors (cppreference)](http://en.cppreference.com/w/cpp/language/move_constructor)

ムーブされた残骸に対しても呼ばれるデストラクタ
----------------------------------------------

ムーブされた残り滓`a = std::move(b)`の`b`のデストラクタは呼ばれる:

```cpp
#include <iostream>

class A {
public:
  A() { std::cout << "Constructor " << std::endl; }
  A(const A &a) { std::cout << "Copy Constructor " << std::endl; }
  A(A &&a) noexcept { std::cout << "Move Constructor " << std::endl; }
  ~A() { std::cout << "Destructor " << std::endl; }
};

A create_A() {
  A tmp;                 // call constructor
  return std::move(tmp); // call move constructor
                         // call destructor
}

int main() {
  A a = create_A();
  return 0;
  // call destructor
}
```

この出力は以下のようにデストラクタが2回呼ばれている事に注意する：

```console
Constructor 
Move Constructor 
Destructor 
Destructor 
```

付けられる時はnoexceptを必ず付けよう
------------------------------------

ムーブコンストラクタがnoexceptであるかを判定しているアルゴリズムがあります。
例えば`std::vector`の`push_back`ではGCC4.7以降で`std::move_if_noexcept`を使用するため、
`noexcept`のついていないムーブコンストラクタは使われません。
自作クラスのムーブコンストラクタを書く際は注意しましょう。

### 参考HP
- [ムーブコンストラクタにnoexceptを付けないと呼ばれないことがある (Faith and Brave - C++で遊ぼう)](http://faithandbrave.hateblo.jp/entry/20120328/1332921033)
- [12.5.4 Declare noexcept the move constructor and move assignment operator (High Integrity C++ Coding Standard)](http://www.codingstandard.com/rule/12-5-4-declare-noexcept-the-move-constructor-and-move-assignment-operator/)

move assignment operator (移動代入演算子)
-----------------------------------------

効率的な実装の方法として以下の方法が考えられます:

1. 先にmove assignment operator `operator=(T&&)` を定義する
2. move constructorを `T(T&& other) noexcept { *this = std::move(other); }` で定義する

こうすれば同じ処理を重複なく書けます。
こちらにも`noexcept`をつける事を忘れずに。また自己代入に注意しましょう。

```cpp
T& operator=(T&& other) noexcept{
  if(this != &other){
    // moveの処理
  }
  return *this;
}
```

### 参考HP
- [方法: 移動コンストラクターを記述する (Microsoft developer network)](https://msdn.microsoft.com/ja-jp/library/dd293665.aspx)