今回は前回のshared_ptrの説明の最後にちょっとだけ顔を出したunique_ptrについて。
ちなみにWikipediaを見てみるとわかるとおり、
また、unique_ptrがauto_ptrの代わりとして導入され、auto_ptrは非推奨とされる。unique_ptrはauto_ptrの全機能を提供するが、左辺値からの暗黙的な移動の際に起こる挙動が異なる。unique_ptrは、C++0xのMove Semanticsを用いたコンテナになっている。
と書かれている通り、auto_ptrと動きのほとんどは変わりません。
ただし、書いてある通りですし最新のg++などで試してもわかるとおり、左辺値からの挙動が異なっています。
左辺値からのコピーはコンパイルエラーとなります。
#include <memory> #include <iostream> class Sample { public: Sample(int number) { num = number; std::cout << "number(" << num << "):const." << std::endl; } ~Sample() { std::cout << "number(" << num << "):dest." << std::endl; } int num; }; int main() { std::unique_ptr<Sample> ptr1(new Sample(1)); std::cout << ptr1->num << std::endl; std::unique_ptr<Sample> ptr2 = ptr1; // コンパイルエラー return 0; }
auto_ptrのときはコピー元を破壊するという『破壊的コピー』を行っていたのでその辺りは違うと思います。
/* 略 */ int main() { std::auto_ptr<Sample> ptr1(new Sample(1)) std::auto_ptr<Sample> ptr2 = ptr2; int a = ptr2->num; // もちろんダングリング・ポインタなのでエラー return 0; }
しかしながら、右辺値なら移動することができます。
つまり、std::move()をもちいて左辺値を右辺値にしてから移動することはできます。
もちろんその後に右辺値にしたものは使えませんが。
/* 略 */ int main() { std::unique_ptr<Sample> ptr1(new Sample(1)); std::cout << ptr1->num << std::endl; std::unique_ptr<Sample> ptr2 = std::move(ptr1); // これはOK std::cout << ptr1->num << std::endl; // これは実行時エラー return 0; }
ここまで来て、なんだかauto_ptrの出番は少なくなりそうに見えてきましたが、さらにC++0xからは非推奨のものとなるみたいです。(deprecated扱いになってるらしい)
今までのコードもその辺は注意しておかないといけないですから、C++0xはC++を使う皆さんは知らないでは済まされなさそうです。
ところで、shared_ptrもunique_ptrもどちらにもカスタムデリータ(デストラクタを外付けにできる)の指定については触れていないので、今度まとめて書いてみようかなと思います。
ちなみに最近卒論で(というよりは卒業課題ですが)、忙しくてあんまり他の勉強ができてないさびしい現状です。
3年生のころまであった余裕がほしいと思ってしまいますね。