c++ 生ポインタ スマートポインタとは何ですか?いつスマートポインタを使用しますか?




スマートポインタ 生ポインタ (12)

私は上記の質問にもう一つの点を追加したいと思います。スマートポインタstd :: shared_ptrには添え字演算子がなく、ポンター演算をサポートしていません。get()を使って組み込みポインタを取得できます。

スマートポインタとは何ですか?いつスマートポインタを使用しますか?


スマートポインタは、ポインタ自体が範囲外になり、それが指すものが削除される場合を除いて、 "char *"のような通常の(型付きの)ポインタのようなものです。 通常のポインタのように、 " - >"を使って使うことができますが、データへの実際のポインタが必要な場合は使用できません。 そのためには、 "&* ptr"を使用することができます。

これは以下の場合に便利です。

  • 新しいもので割り振られなければならないが、そのスタック上に何かと同じ生涯を持たせたいオブジェクト。 オブジェクトがスマートポインタに割り当てられている場合、その関数/ブロックを終了すると削除されます。

  • クラスのデータメンバー。オブジェクトが削除されると、所有者のデータもデストラクタに特別なコードがなくても削除されるようになります(デストラクタが仮想であることを確認する必要があります。 。

次の場合にスマートポインタを使用したくない場合があります。

  • ...ポインタは実際にデータを所有すべきではありません。つまり、単にデータを使用していても、ポインタを参照している関数にポインタを残しておく必要があります。
  • ...スマートポインタ自体はある時点で破壊されることはありません。 動的に割り当てられているが明示的に削除されないオブジェクトの中など、決して破壊されないメモリ内には置かないようにします。
  • ... 2つのスマートポインタが同じデータを指している可能性があります。 (ただし、それを処理するもっとスマートなポインタがあります。これは参照カウントと呼ばれます)。

参照:


スマートポインタは、ポインタのように動作するオブジェクトですが、さらに、構築、破壊、コピー、移動、参照解除を制御します。

自分自身のスマートポインタを実装することもできますが、多くのライブラリではそれぞれ異なる長所と短所を持つスマートポインタ実装を提供しています。

たとえば、 Boostは次のスマートポインタ実装を提供します。

  • shared_ptr<T>は、オブジェクトがもはや必要でないときを決定するために参照カウントを使用するTへのポインタです。
  • scoped_ptr<T>はスコープ外に出たときに自動的に削除されるポインタです。 割り当てはできません。
  • intrusive_ptr<T>は別の参照カウントポインタです。 shared_ptrよりも優れたパフォーマンスを提供しますが、独自の参照カウントメカニズムを提供するにはT型が必要です。
  • weak_ptr<T>はweakポインタです。循環参照を避けるためshared_ptrと連携して動作します。
  • shared_array<T>shared_ptrに似ていますが、 T配列に対してです。
  • scoped_array<T>scoped_array<T>似ていますが、 T配列に対してです。

これらはそれぞれのリニアな説明の1つで、必要に応じて使用できます。詳細と例については、Boostのドキュメントを参照してください。

さらに、C ++標準ライブラリには3つのスマートポインタが用意されています。 固有の所有権のためのstd::unique_ptr 、共有所有権のためのstd::shared_ptr 、およびstd::weak_ptrstd::auto_ptrはC ++ 03に存在しましたが、廃止予定です。


スマートポインタは、ポインタのような型で、自動メモリ割り当て解除、参照カウントなどの機能を追加しています。

小さなイントロはページ上にありますスマートポインタ - 何、なぜ、どちら?

シンプルなスマートポインタ型の1つは、 std::auto_ptr (C ++標準の20.4.5章)です。スコープ外のときにメモリを自動的に解放し、例外がスローされたときの単純なポインタの使用よりも堅牢ですフレキシブル。

もう1つの便利な型はboost::shared_ptrこれは参照カウントを実装し、オブジェクトへの参照が残っていないときにメモリを自動的に解放します。 これはメモリリークを回避するのに役立ち、 RAIIを実装するのに使いやすいです。

件名はDavid Vandevoordeの「C ++ Templates:The Complete Guide」、Nicolai M. Josuttisの章、第20章「スマートポインタで詳しく説明されています。 一部のトピックでは、

  • 例外からの保護
  • ホルダー、(注意: std::auto_ptrは、この種のスマートポインタの実装です)
  • リソース獲得は初期化です (これはC ++での例外安全なリソース管理によく使用されます)
  • ホルダーの制限
  • 参照カウント
  • 同時カウンタアクセス
  • 破壊と解放

最近のC ++の今日の簡単な答えは次のとおりです。

  • スマートポインタとは何ですか?
    値はポインタのように使うことができるが、自動メモリ管理の追加機能を提供する型です:スマートポインタがもはや使用されていないとき、それが指すメモリは割り当て解除されます( Wikipediaの詳細な定義も参照してください)。
  • いつ使うべきですか?
    コードでは、メモリの所有権を追跡すること、割り当てまたは割り当てを解除すること、 スマートポインタは、これらのことを明示的に実行する必要性を保存することがあります。
  • しかし、どのスマートポインタをこれらのケースで使うべきですか?
    • 同じオブジェクトへの複数の参照を保持するつもりがない場合は、 std::unique_ptr使用します。 たとえば、スコープを入力するときに割り当てられ、スコープを終了するときに割り当てが解除されるメモリへのポインタに使用します。
    • オブジェクトを複数の場所から参照したい場合は、 std::shared_ptr使用します。これらの参照がすべて消えるまで、オブジェクトを割り当て解除しないようにします。
    • 複数の場所からオブジェクトを参照したい場合は、 std::weak_ptr使用してください。無視したり解除したりすることができます(参照解除しようとするとオブジェクトがなくなったことに気付くでしょう)。
    • boost:: smartポインタやstd::auto_ptrは特別な場合を除いて使用しないでください。
  • ねえ、私はどちらを使うのか尋ねなかった!
    ああ、あなたは本当にしたいと思って、それを認めます。
  • だからいつ定期的なポインタを使うべきですか?
    主にメモリの所有権を知らないコードです。 これは通常、他の場所からポインタを取得し、その実行を引き継ぐポインタのコピーを割り当て、割り当て解除、または格納しない関数にあります。

TをこのチュートリアルのクラスとするPointers in C ++は3つのタイプに分けることができます:

1) 生ポインタ

T a;  
T * _ptr = &a; 

それらはメモリ内のある場所にメモリアドレスを保持します。 プログラムが複雑になりにくいため、慎重に使用してください。

constデータまたはアドレスを持つポインタ{逆方向に読み込む}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

constのデータ型Tへのポインタ。 つまり、ポインタを使用してデータ型を変更することはできません。 すなわち*ptr1 = 19 ; 動作しないでしょう。 しかし、あなたはポインタを動かすことができます。 すなわち、 ptr1++ , ptr1-- ; 等が動作します。 後方に読む:const型のT型へのポインタ

  T * const ptr2 ;

データ型Tへのconstポインタ。 ポインタを移動することはできませんが、ポインタが指す値を変更することができます。 すなわち、 *ptr2 = 19は動作しますが、 ptr2++ ; ptr2--は動作しptr2++ ; ptr2-- ptr2++ ; ptr2--などは動作しません。 後方に読む:const型Tへのポインタ

const T * const ptr3 ; 

constデータ型Tへのconstポインタ。 つまり、ポインタを移動することも、データ型ポインタをポインタにすることもできません。 すなわち、 ptr3-- ; ptr3++ ; *ptr3 = 19; 動作しないでしょう

3) スマートポインタ :{ #include <memory> }

共有ポインタ

  T a ; 
     //shared_ptr<T> shptr(new T) ; not recommended but works 
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of " 
things " pointing to it. 
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn(); 

    //
     shptr.reset() ; // frees the object pointed to be the ptr 
     shptr = nullptr ; // frees the object 
     shptr = make_shared<T>() ; // frees the original object and points to new object

参照カウントを使用して実装され、ポインタによって指し示されるオブジェクトを指している「物」の数を追跡します。 このカウントが0になると、オブジェクトは自動的に削除されます。つまり、オブジェクトを指すshare_ptrがすべてスコープから外れると、オブジェクト化されたオブジェクトが削除されます。 これは、あなたがnewを使って割り当てたオブジェクトを削除しなければならないという頭痛を取り除きます。

Weak Pointer:共有ポインタを使用するときに発生する巡回参照を処理するのに役立ちます。2つの共有ポインタが指し示す2つのオブジェクトがあり、共有ポインタが互いに共有ポインターを指している場合、巡回参照が存在し、共有ポインタが有効範囲外になると削除されます。 これを解決するには、内部メンバーをshared_ptrからweak_ptrに変更します。 注意:weakポインタが指す要素にアクセスするにはlock()を使います。これはweak_ptrを返します。

T a ; 
shared_ptr<T> shr = make_shared<T>() ; 
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr 
wk.lock()->memFn() ; // use lock to get a shared_ptr 
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

参照: std :: weak_ptrはいつ有用ですか?

ユニークポインタ:排他的所有権を持つ軽量スマートポインタ。 ポインタがオブジェクト間でオブジェクトを共有することなく、ポインタが一意のオブジェクトを指しているときに使用します。

unique_ptr<T> uptr(new T);
uptr->memFn(); 

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr 

ユニークなptrが指すオブジェクトを変更するには、move semanticsを使用します

unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1); 
// object pointed by uptr2 is deleted and 
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null 

参考文献:本質的にconstポインタ、すなわちconstであり、より良い構文では動かすことができないポインタであってもかまいません。

参照: C ++のポインタ変数と参照変数の違いは何ですか?

r-value reference : reference to a temporary object   
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified 

参考: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ : https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQこの質問を指摘してくれたAndreに感謝しhttps://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ


Chris、Sergdev、Llyodの定義は正しい。 私はもっ​​と簡単な定義を好みますが、私の人生を単純に保つだけです。スマートポインタは単に->*演算子をオーバーロードするクラスです。 つまり、あなたのオブジェクトは意味的にはポインタのように見えますが、参照カウント、自動破壊などを含め、よりクールなものにすることができます。ほとんどの場合、 shared_ptrauto_ptrで十分ですが、小さな独自性のセットに従います。


既存の回答は良いですが、解決しようとしている問題に対するスマートポインタが(完全な)答えではない場合、何をすべきかをカバーしていません。

スマートポインタを使用する他のもの(他の回答でもうまく説明されている)の中で、関数の戻り値の型として抽象クラスを使用するには、可能な解決策があります。 この質問の重複としてマークされています。 しかし、抽象的な(または実際には、どんな)基本クラスをC ++の戻り値の型として指定したいのであれば、最初の質問は「あなたはどういう意味ですか?」です。 ブースト・ポインタ・コンテナ・ライブラリのドキュメントには、C ++での慣用的なオブジェクト指向プログラミング(およびこれが他の言語とはどのように異なるか)についての良い議論があります 。 要約すると、C ++では所有権について考える必要があります。 どのスマートポインタが役立つのですか?唯一の解決策ではありません。常に完全な解決策ではありません(多形コピーは得られません)。また、インターフェイスで公開したい解決策ではありません。インターフェイスのようなロット)。 たとえば、参照を返すだけで十分かもしれません。 しかし、これらのすべてのケース(スマートポインタ、ポインタコンテナ、または単純に参照を返す)では、戻りから何らかの形式の参照に変更しました 。 本当にコピーが必要な場合は、より多くの定型的な "イディオム"を追加するか、C ++の慣用的な(またはその他の)OOPを超えて、 Adobe PolyBoost.TypeErasureようなライブラリを使用してより一般的な多型に移行する必要があります。


スマートポインタは、メモリの割り当て解除、リソースの共有、転送について心配する必要のないものです。

これらのポインタは、Javaでの割り当てと同様に使用できます。 Javaのガベージコレクタではトリックを行いますが、スマートポインタではトリックはデストラクタによって行われます。


スマートポインタは、指されているオブジェクトの存続時間を管理するために、 '未処理'(または '裸の)C ++ポインタをラップするクラスです。 単一のスマートポインタ型は存在しませんが、それらのすべてが実際の方法で生ポインタを抽象化しようとします。

スマートポインタは、生ポインタよりも優先されるべきです。 ポインタを使う必要があると感じたら、通常はスマートポインタを使いたいと思うので、オブジェクトを削除してメモリを漏らすことを忘れてしまった生ポインタの多くの問題を緩和することができます。

生ポインタでは、プログラマはオブジェクトがもはや役に立たないときにオブジェクトを明示的に破棄しなければならない。

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

比較によるスマートポインタは、オブジェクトがいつ破棄されるかに関するポリシーを定義します。 それでもオブジェクトを作成する必要がありますが、オブジェクトを破棄する心配はありません。

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

最も単純なポリシーには、 boost::scoped_ptrstd::unique_ptrなどのスマートポインタラッパーオブジェクトのスコープが含まれます。

void f()
{
    {
       boost::scoped_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // boost::scopted_ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

scoped_ptrインスタンスはコピーできないことに注意してください。 これにより、ポインタが複数回(間違って)削除されることがなくなります。 しかし、あなたが呼び出す他の関数にその参照を渡すことができます。

スコープ付きポインターは、オブジェクトの有効期間を特定のコードブロックに結びつける場合や、メンバーデータとして別のオブジェクト内に組み込んだ場合に、他のオブジェクトの有効期間を設定する場合に便利です。 オブジェクトは、包含するコードブロックが終了するまで、または包含するオブジェクト自体が破棄されるまで存在します。

より複雑なスマートポインタポリシーには、ポインタの参照カウントが含まれます。 これにより、ポインタをコピーすることができます。 オブジェクトへの最後の「参照」が破棄されると、そのオブジェクトは削除されます。 このポリシーは、 boost::shared_ptrstd::shared_ptrによって実装されています。

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

参照カウントポインタは、オブジェクトの存続期間がはるかに複雑で、特定のコードセクションや別のオブジェクトに直接結び付けられていない場合に非常に役立ちます。

カウントされたポインタを参照することには欠点が1つあります。ダングリングリファレンスを作成する可能性があります。

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

別の可能性は、循環参照を作成することです。

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

boost::shared_ptr<Owner> p1 (new Owner());
boost::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

この問題を回避するために、BoostとC ++ 11はweak_ptrを定義してshared_ptrへの弱い(未カウントの)参照を定義しています。

更新

この答えはかなり古いもので、その時点でBoostライブラリによって提供されたスマートなポインタであった時は「良い」ものだった。 C ++ 11以降、スタンダードライブラリは十分なスマートポインタ型を提供していますので、 std::unique_ptrstd::shared_ptr 、およびstd::weak_ptrの使用を優先してください。

std::auto_ptrもあります。 これはスコープ付きポインタに非常によく似ていますが、 "特別な"危険なコピー機能もあります。これは意外にも所有権を移します! 最新の標準では推奨されていないので、使用しないでください。 代わりにstd::unique_ptr使用してください。

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

スマートポインタはクラスであり、通常のポインタのラッパーです。 スマートポイントのライフサークルは、通常のポインタとは異なり、参照カウント(スマートポインタオブジェクトが割り当てられている時間)に基づいています。 したがって、スマートポインタが別のスマートポインタに割り当てられると、内部参照カウントはプラスになります。 オブジェクトがスコープから外れると、参照カウントからマイナスが差し引かれます。

自動ポインタも同様に見えますが、スマートポインタとはまったく異なります。 これは、自動ポインタオブジェクトが可変スコープから出るたびにリソースの割り当てを解除する便利なクラスです。 ある程度までは、(動的に割り当てられたメモリへの)ポインタは、スタック変数(コンパイル時に静的に割り当てられる)と同様の働きをします。


同様の回答のリンクは次のとおりですhttp://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html : http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

スマートポインタは、通常のポインタのように動作し、外見や感触は向上しますが、より多くの機能を提供するオブジェクトです。 C ++では、スマートポインタは、ポインタをカプセル化して標準のポインタ演算子をオーバーライドするテンプレートクラスとして実装されています。 彼らは通常のポインタよりも多くの利点があります。 それらは、ヌルポインタまたはヒープオブジェクトへのポインタとして初期化されることが保証されています。 ヌルポインタによる間接参照がチェックされます。 削除は一切必要ありません。 オブジェクトへの最後のポインタがなくなると、オブジェクトは自動的に解放されます。 これらのスマートポインタの重要な問題の1つは、通常のポインタとは異なり、継承を尊重しないことです。 スマートポインタは多態性コードには魅力がありません。 スマートポインタの実装例を以下に示します。

例:

template <class X>
class smart_pointer
{
          public:
               smart_pointer();                          // makes a null pointer
               smart_pointer(const X& x)            // makes pointer to copy of x

               X& operator *( );
               const X& operator*( ) const;
               X* operator->() const;

               smart_pointer(const smart_pointer <X> &);
               const smart_pointer <X> & operator =(const smart_pointer<X>&);
               ~smart_pointer();
          private:
               //...
};

このクラスは、タイプXのオブジェクトへのスマートポインタを実装します。オブジェクト自体はヒープ上にあります。 それを使用する方法は次のとおりです。

smart_pointer <employee> p= employee("Harris",1333);

他のオーバーロードされた演算子と同様に、pは通常のポインタのように動作し、

cout<<*p;
p->raise_salary(0.5);






c++-faq