本記事ではムーブコンストラクタの概要や仕組み、目的、実装時の注意点について解説する。ムーブセマンティクスの概念も理解できる一石二鳥の内容となっている。後半ではコンテナクラスの動作を高速化するための手順と原理を解説する。constructor)はオブジェクトの内部値を新たなオブジェクトに移動/譲渡するための特殊なコンストラクタである。コピーコンストラクタが内部表現のコピーを実現するのに対し、ムーブコンストラクタでは内部表現の移動を実現する点が異なる。ムーブコンストラクタはT(T&&)という形式で宣言する。nullptr)する必要がある。}};ムーブコンストラクタの定義によって、オブジェクトが保有する値の所有権を、他のオブジェクトへ簡単に移転することが可能になる。ムーブセマンティクスの実現が可能となる。値をコピーするのではなく、移動することが可能となる。以下はムーブコンストラクタの使用例である。変数aにはなんの影響もない(ポインタa.pはまだ解放されていない)ムーブコンストラクタを呼び出すためには、コンストラクタ引数に対して右辺値参照(&&)を渡す必要がある。そのためにはstd::move()やstatic_cast<A&&>()によるキャスト処理でもって右辺値参照を明示する必要がある。基本的にムーブコンストラクタが呼び出された場合、譲渡元オブジェクトは空の状態となる。コピーコンストラクタの場合はオブジェクトの完全な複製を実現するのに対し、ムーブコンストラクタでは元のオブジェクトの値を完全に譲渡するという特徴がある。譲渡の際には、元のオブジェクトのその後振る舞いによってムーブ先のオブジェクトに影響が及ばないようにしなければならない。変数aにはなんの影響もない(ポインタa.pはまだ解放されていない)これで値の所有権は完全に新しいオブジェクトへ移動したことになる。p;処理ではnullptrに対する処理が働くことになり、メモリ解放処理は無効化される。aのメンバ変数pは何の影響も受けることなく、ポインタオブジェクトa.pも有効なままとなる。aのデストラクタが呼ばれるタイミングで解放されることになる。ムーブセマンティクス今回説明したサンプルコードは、実はとても単純なことしかしていない。aに移動したというだけの話である。semantics)」と呼ばれている。C++のムーブセマンティクスでは、所有権の移動を右辺値参照へのキャストとその受け取りという明確な記法と作法を用いて表現している点が特徴的である。つまるところ、ムーブセマンティクスとは、所有権の移動を表現するための何かしらの作法のことを指す。そのため、ムーブセマンティクスはムーブコンストラクタに限らず、様々な場面での実現も可能となっている。初期化済みのオブジェクト変数同士でムーブ処理を行うこともできる。"01"ムーブ代入演算子は独自に定義することもできる。nullptr);C言語によるムーブセマンティクス同等のムーブセマンティクスはC言語でも実現できる。free(b);C++におけるムーブコンストラクタや右辺値参照の仕組みはこのムーブセマンティクスを実現しやすくするための仕組みであるとも言える。コピーコンストラクタによるムーブセマンティクスなお推奨はされていないが、コピーコンストラクタでムーブセマンティクスを実現することもできる。以下は現在非推奨となっているstd::auto_ptr<T>クラスの実装例である。上記の例では、譲渡の方法が一般的なコピーコンストラクタ呼び出しと同じ記法になっている点が少し厄介である。これは注意して使用しないと勘違いやミスの原因になる可能性がある。以下のように、意図しないタイミングで値の移動が行われてしまう危険性もある。クラッシュするauto_ptrのコピーコンストラクタを未定義にし、代わりにムーブコンストラクタを実装することで、この問題を回避することができる。その場合、ムーブが必要な場面ではstd::moveでムーブセマンティクスを明示しなければならなくなるが、そのほうが明確で安全である。実は、右辺値参照によるムーブセマンティクスの明示は、所有権の保護と管理を厳格に行うための仕組みとしても機能しているのである。C++標準ライブラリのstd::unique_ptr<T>クラスはまさにその対策が取り入れられており、現在ではstd::auto_ptr<T>の後継として広く使われている。auto_ptrはこれらの危険性から現在では非推奨の機能となっているため、誤って使用しないように注意したい。譲渡元オブジェクトのメンバがムーブコンストラクタに対応している場合は、メンバに対してムーブ処理を施さなければならない場面と不要な場面に分かれるため注意が必要である。b(std::move(A()));このように、コピーコンストラクタを定義していないクラスでは、ムーブコンストラクタの定義を省略できる。メンバに対するムーブ処理も自動で施されるようになる。b(std::move(A()));ただしクラス側でコピーコンストラクタを独自定義した場合にはムーブコンストラクタの暗黙的な定義(default定義)がされなくなるため注意したい。b(std::move(A()));)を行うと、ムーブコンストラクタの代わりにコピーコンストラクタが呼ばれるようになる。default;という形でdefault指定を行えばよい。ムーブコンストラクタが呼ばれるコンテナクラスとの関係と高速化ムーブコンストラクタを実装すると、std::vector等のコンテナクラスの動作が高速化する場合がある。多くのコンテナクラスでは要素追加時にバッファ(メモリ)の再確保や要素の再配置が行われるが、その際に各既存要素のコピーコンストラクタが呼ばれてしまうという問題がある。要素型側でムーブコンストラクタを定義することで、このコピーコンストラクタ呼び出しを回避することができ、代わりにより処理コストの低いムーブコンストラクタが呼ばれるようになる。コピーコンストラクタのコピーコストや処理時間が大きくなるような場合はムーブコンストラクタの実装を検討してみると良い。C++高速化の有効な手段となり得る。コンテナ対応時の注意点ただ注意点として、ムーブコンストラクタはnoexceptキーワードを指定した形で定義しなければならない。}};例外指定は「例外を許可しない」形で指定する必要がある(noexceptまたはnoexcept(true)と記述する)。例外指定を適切に指定しないと、要素の再代入時にムーブコンストラクタが呼ばれなくなり、代わりに従来のコピーコンストラクタ呼び出しが行われるようになってしまう。