What is it, naokirin?

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

今回はweak_ptr。

weak_ptrは弱参照の概念のためのスマートポインタです。

shared_ptrでは循環参照の問題を解決できません。

#include <iostream>
#include <memory>

class Sample
{
public:
    Sample() {}
    ~Sample() {}
    
    std::shared_ptr<Sample> ptr;
};

int main()
{
    std::shared_ptr<Sample> p1(new Sample);
    std::shared_ptr<Sample> p2(new Sample);

    p1->ptr = p2;
    p2->ptr = p1;

    return 0;
} // 解放されない



しかし、弱参照であるweak_ptrは参照カウントを行わないため、参照がある無しに関わらずスコープを抜けるとインスタンスを解放します。

#include <iostream>
#include <memory>

class Sample
{
public:
    Sample() {}
    ~Sample() {}
    
    std::weak_ptr<Sample> ptr;
};

int main()
{
    std::shared_ptr<Sample> p1(new Sample);
    {
        std::shared_ptr<Sample> p2(new Sample);

        p1->ptr = p2;
        p2->ptr = p1;
    } // p2のインスタンスは解放

    return 0;
} // p1のインスタンスは解放



もちろん、これはダングリング・ポインタを参照する危険が伴うことになりますが、次のようなチェックを行うことで防ぐことができます。

int main()
{
    std::shared_ptr<Sample> p1(new Sample);
    {
        std::shared_ptr<Sample> p2(new Sample);

        p1->ptr = p2;
        p2->ptr = p1;
    } // p2のインスタンスは解放

    /* lock()で生存を確認できる */
    if( auto q = p1->ptr.lock() ){
        /* p1->ptrはまだ生存(もちろんこのコードではここには来ない) */
    } else{
        /* p1->ptrは無効 */
    }

    return 0;
} // p1のインスタンスは解放



ちなみにlock()はshared_ptrを返すメンバ関数です。



weak_ptrは生ポインタの特性にとてもよく似ていますが、スコープを抜けるときに確実にインスタンスの解放を行うため、生ポインタに比べるとメモリリークの危険性が低くなっています。


使用頻度としてはunique_ptr > shared_ptr > weak_ptrを想定しているようです。



旧コメント:
些細な言葉の使い方の違いですが


null pointer というより dangling pointer と表現したほうがいい場所が、幾つかあると思います。
null pointer なら、生ポインタであっても if を使えば簡単に回避できますし。

2011-01-24 18:42 | SubaruG


Re: 些細な言葉の使い方の違いですが
そうですね、null pointerというよりはdangling pointerと表現すべきですね。直しておきました。

2011-01-24 18:52 | Naoki Rin