pointers - c++ スマートポインタ 配列 - スマートポインターとはどのようなもので、どのような場合に使用すればよいのでしょうか?

Shared_ptr 配列 / c++ / c++11 / smart-pointers / c++-faq

スマートポインターとはどのようなもので、どのような場合に使用すればよいのでしょうか?

user2357112 supports Monica



Answer #1

この答えはかなり古いので、Boostライブラリによって提供されたスマートポインタであった当時の「良い」ものを説明しています。C ++ 11以降、標準ライブラリは十分なスマートポインター型を提供しているため、 std::unique_ptr std::shared_ptr 、および std::weak_ptr の使用を優先する必要があります。

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; //所有権をコピーして譲渡します。
                                 // p1が空に設定されます!
p2->DoSomething(); //動作します。
p1->DoSomething(); //ああああ。うまくいけば、いくつかのNULLポインタ例外が発生します。

生のポインタでは、プログラマはオブジェクトが役に立たなくなったときに、明示的にオブジェクトを破棄しなければなりません。

//いくつかの目標を達成するためにオブジェクトを作成する必要があります
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); //オブジェクトを何らかの方法で使用します
delete ptr; //オブジェクトを破棄します。それで終わりました。
//待って、DoSomething()が例外を発生させたらどうなるでしょうか...?

それに比べてスマートポインターは、オブジェクトをいつ破壊するかというポリシーを定義しています。オブジェクトを作成する必要はありますが、破壊することを心配する必要はありません。

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); //オブジェクトを何らかの方法で使用します。

//オブジェクトの破壊は、状況に応じて発生します
//スマートポインタクラスが使用するポリシー。

// DoSomething()でも破壊が発生します
//例外を発生させます

使用されている最も単純なポリシーには、 boost::scoped_ptr または std::unique_ptr によって実装されるような、スマートポインターラッパーオブジェクトのスコープが含まれます。

使用されている最も単純なポリシーには、 boost::scoped_ptr または std::unique_ptr によって実装されるような、スマートポインターラッパーオブジェクトのスコープが含まれます。

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // ptrがスコープ外になります-
      // MyObjectは自動的に破棄されます。

    // ptr-> Oops(); //コンパイルエラー: "ptr"が定義されていません
                    //スコープ内にないため。
}
void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; //素敵な短いエイリアス
    MyObjectPtr p1; // 空の

    {
        MyObjectPtr p2(new MyObject());
        //作成されたオブジェクトへの「参照」が1つあります
        p1 = p2; //ポインタをコピーします。
        //オブジェクトへの参照が2つあります。
    } // p2は破棄され、オブジェクトへの参照が1つ残ります。
} // p1は破棄され、参照カウントはゼロのままになります。
  //オブジェクトが削除されます。

カウントされたポインタを参照することには1つの欠点があります。それは、ぶら下がっている参照を作成する可能性です。

//ヒープ上にスマートポインタを作成します
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
//うーん、スマートポインタを破棄するのを忘れました。
//そのため、オブジェクトが破壊されることはありません!

もう一つの可能性は、円形の参照を作成することです。

struct Owner {
   std::shared_ptr<Owner> other;
};

std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1はp2を参照します
p2->other = p1; // p2はp1を参照します

//おっと、p1とp2の参照カウントがゼロになることはありません!
//オブジェクトが破壊されることはありません!