Search on the blog

2014年3月27日木曜日

C++11のスマートポインタを使ってみる

 C++11から使えるようになったスマートポインタを使って遊んでみました。なかなか面白いです。
  1. unique_ptr
  2. shared_ptr
  3. weak_ptr
の順で使い方を見ていきます。

unique_ptr
unique_ptrは自身がスコープアウトした時点で、管理しているオブジェクトをdeleteします。
 その名のとおり、あるオブジェクトを管理するunique_ptrは一意でなければいけません。よってunique_ptr間でオブジェクトの共有は出来ません。

とりあえず使ってみます。
#include <iostream>
#include <memory>

using namespace std;

struct hoge {
    hoge() {
        cout << "a hoge instance is constructed" << endl;
    }

    ~hoge() {
        cout << "a hoge instance is destructed" << endl;
    }

    void doSomething() {
        cout << "a hoge instance does something" << endl;
    }
};

int main(int argc, char **argv) {

    cout << "start block" << endl;
    {
        unique_ptr<hoge> ptr(new hoge());
        ptr->doSomething();
    }
    cout << "end block" << endl;

    return 0;
}
実行すると、

start block
a hoge instance is constructed
a hoge instance does something
a hoge instance is destructed
end block

のようになります。hogeを管理しているunique_ptrがスコープアウトした時点でhogeのデストラクタが自動で呼ばれているのが分かります。

 複数のunique_ptrでオブジェクトを共有することは出来ないので、以下のようなソースはコンパイルエラーになります。
int main(int argc, char **argv) {
    unique_ptr<hoge> ptr(new hoge());
    unique_ptr<hoge> qtr = ptr;
    return 0;
}

shared_ptr
次にshared_ptrを使ってみます。shared_ptrはオブジェクトを共有できます。管理しているオブジェクトの参照カウントが0になった時点でオブジェクトを自動消去します。

先ほどと同じhogeを使って実験してみます。
int main(int argc, char **argv) {

    shared_ptr<hoge> ptr;

    cout << "start block" << endl;
    {
        shared_ptr<hoge> qtr(new hoge());
        ptr = qtr;
        qtr->doSomething();
    }
    cout << "end block" << endl;

    return 0;
}
実行結果は以下のようになります。

start block
a hoge instance is constructed
a hoge instance does something
end block
a hoge instance is destructed

 hogeはブロック内でnewされます。qtrがhogeを所有しているため、hogeの参照カウントは1です。
その後、ptr = qtrで、ptrもhogeを参照することになります。ここでhogeの参照カウントは2になります。
ブロックを抜けると、qtrがスコープアウトするため、参照カウントが1になります。
最後に、main関数を抜ける時点でptrがスコープアウトし、参照カウントが0になります。
参照カウントが0になった時点で、hogeがdeleteされます。

 shared_ptrの参照カウントは、shared_ptr::use_count()メソッドで取得できます。

weak_ptr
最後にweak_ptrです。Javaの弱参照と似たような感じです。weak_ptrはオブジェクトを共有できますが、weak_ptrによる参照は参照カウントには影響しません。よって、weak_ptrが参照しているオブジェクトが既に削除されてしまっているという場合もあります。

int main(int argc, char **argv) {

    weak_ptr<hoge> ptr;

    cout << "start block" << endl;
    {
        shared_ptr<hoge> qtr(new hoge());
        ptr = qtr;
        cout << ptr.use_count() << endl;
        qtr->doSomething();
    }
    cout << "end block" << endl;

    return 0;
}
を実行すると、

start block
a hoge instance is constructed
1
a hoge instance does something
a hoge instance is destructed
end block

と表示されます。weak_ptrが参照カウンタに関与しないことが分かります。
また、weak_ptrによる参照が存在しても参照カウンタが0になった時点でオブジェクトがdeleteされていることが分かります。

0 件のコメント:

コメントを投稿