What is it, naokirin?

C++0xの機能(unique_ptr/スマートポインタ)

今回は前回の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++0xC++を使う皆さんは知らないでは済まされなさそうです。


ところで、shared_ptrもunique_ptrもどちらにもカスタムデリータ(デストラクタを外付けにできる)の指定については触れていないので、今度まとめて書いてみようかなと思います。



ちなみに最近卒論で(というよりは卒業課題ですが)、忙しくてあんまり他の勉強ができてないさびしい現状です。
3年生のころまであった余裕がほしいと思ってしまいますね。