logo

C++ のスマート ポインター

前提条件: C++ のポインター

ポインタは、ヒープ メモリなど、プログラムの外部にあるリソースにアクセスするために使用されます。したがって、ヒープ メモリにアクセスするには (ヒープ メモリ内に何かが作成される場合)、ポインタが使用されます。外部リソースにアクセスするときは、リソースのコピーを使用するだけです。それに変更を加える場合は、コピーしたバージョンで変更するだけです。ただし、リソースへのポインターを使用すると、元のリソースを変更できます。



通常のポインタの問題

C++ の通常のポインターに関するいくつかの問題は次のとおりです。

    メモリ リーク: これは、プログラムによってメモリが繰り返し割り当てられたにもかかわらず解放されなかった場合に発生します。これにより、過剰なメモリ消費が発生し、最終的にはシステムのクラッシュにつながります。 ダングリング ポインタ: ダングリング ポインタは、ポインタの値を変更せずにオブジェクトがメモリから割り当て解除されるときに発生するポインタです。ワイルド ポインタ: ワイルド ポインタは、宣言されてメモリが割り当てられるポインタですが、有効なオブジェクトまたはアドレスを指すように初期化されることはありません。データの不整合: データの不整合は、一部のデータがメモリに保存されているにもかかわらず、一貫した方法で更新されていない場合に発生します。バッファ オーバーフロー: ポインタを使用して、割り当てられたメモリ ブロックの外側にあるメモリ アドレスにデータを書き込む場合。これによりデータが破損し、悪意のある攻撃者によって悪用される可能性があります。

例:

C++








// C++ program to demonstrate working of a Pointers> #include> using> namespace> std;> class> Rectangle {> private>:> >int> length;> >int> breadth;> };> void> fun()> {> >// By taking a pointer p and> >// dynamically creating object> >// of class rectangle> >Rectangle* p =>new> Rectangle();> }> int> main()> {> >// Infinite Loop> >while> (1) {> >fun();> >}> }>

>

>

出力

Memory limit exceeded>

説明: 機能中 楽しい を指すポインタを作成します。 矩形 物体。オブジェクト 矩形 2 つの整数が含まれており、 長さ、 そして 。関数のとき 楽しい 終了すると、p はローカル変数であるため破棄されます。ただし、消費したメモリは、使用するのを忘れたため、割り当てが解除されません。 pを削除します。 関数の最後に。つまり、メモリを他のリソースが自由に使用できなくなります。しかし、変数はもう必要ありません。必要なのはメモリです。

機能的には、 主要楽しい 無限ループで呼び出されます。つまり、作り続けるということです p 。メモリはどんどん割り当てられますが、割り当てを解除していないため解放されません。無駄になったメモリは再度使用することはできません。これはメモリリークです。全体 ヒープ この理由により、メモリが使用できなくなる可能性があります。

スマートポインター

ご存知のとおり、無意識のうちにポインターの割り当てを解除しないとメモリ リークが発生し、プログラムのクラッシュにつながる可能性があります。 Java、C# が持つ言語 ガベージコレクションのメカニズム 未使用のメモリを賢く割り当て解除して再度使用できるようにします。プログラマはメモリ リークを心配する必要はありません。 C++ は独自のメカニズムを考え出します。 スマートポインター 。オブジェクトが破棄されると、メモリも解放されます。したがって、スマート ポインターが処理するため、削除する必要はありません。

スマートポインター のような演算子を持つポインターのラッパー クラスです。 * そして -> 過負荷です。スマート ポインター クラスのオブジェクトは、通常のポインターのように見えます。しかし、それとは異なり、 通常のポインタ、 破壊されたオブジェクト メモリの割り当てを解除し、解放することができます。

アイデアは、ポインターを使用してクラスを取ることです。 駆逐艦、 そして、次のようなオーバーロードされた演算子 * そして -> 。オブジェクトがスコープ外に出るとデストラクターが自動的に呼び出されるため、動的に割り当てられたメモリは自動的に削除されます (または参照カウントがデクリメントされる可能性があります)。

例:

C++




// C++ program to demonstrate the working of Smart Pointer> #include> using> namespace> std;> class> SmartPtr {> >int>* ptr;>// Actual pointer> public>:> >// Constructor: Refer> >// techcodeview.com for use of> >// explicit keyword> >explicit> SmartPtr(>int>* p = NULL) { ptr = p; }> >// Destructor> >~SmartPtr() {>delete> (ptr); }> >// Overloading dereferencing operator> >int>& operator*() {>return> *ptr; }> };> int> main()> {> >SmartPtr ptr(>new> int>());> >*ptr = 20;> >cout << *ptr;> >// We don't need to call delete ptr: when the object> >// ptr goes out of scope, the destructor for it is> >// automatically called and destructor does delete ptr.> >return> 0;> }>

>

>

出力

20>

ポインターとスマート ポインターの違い

ポインタ

スマートポインター

ポインタは、メモリ アドレスとそのメモリ位置に関するデータ型情報を保持する変数です。ポインタはメモリ内の何かを指す変数です。 これは、ポインターをラップするスタック割り当てオブジェクトです。スマート ポインタは、平たく言えば、ポインタ、つまりスコープ付きポインタをラップするクラスです。
範囲外に出てもいかなる形でも破壊されない 範囲外に出ると自滅する
ポインターは他の機能をサポートしていないため、あまり効率的ではありません。 スマート ポインタにはメモリ管理の追加機能があるため、より効率的です。
彼らは非常に労働中心/手作業です。 これらは本質的に自動/事前にプログラムされています。

注記: これは次の場合にのみ機能します 整数 。では、オブジェクトごとにスマート ポインターを作成する必要があるのでしょうか? いいえ 解決策はあります テンプレート 。ご覧のとおり、以下のコードでは T どのタイプでもかまいません。

スレッド.デストロイ

例:

C++




// C++ program to demonstrate the working of Template and> // overcome the issues which we are having with pointers> #include> using> namespace> std;> // A generic smart pointer class> template> <>class> T>>>class> SmartPtr {> >T* ptr;>// Actual pointer> public>:> >// Constructor> >explicit> SmartPtr(T* p = NULL) { ptr = p; }> >// Destructor> >~SmartPtr() {>delete> (ptr); }> >// Overloading dereferencing operator> >T& operator*() {>return> *ptr; }> >// Overloading arrow operator so that> >// members of T can be accessed> >// like a pointer (useful if T represents> >// a class or struct or union type)> >T* operator->() {>>ptr; }> };> int> main()> {> >SmartPtr<>int>>ptr(>new> int>());> >*ptr = 20;> >cout << *ptr;> >return> 0;> }>

>

>

出力

20>

注記: スマート ポインタは、ファイル ハンドルやネットワーク ソケットなどのリソースの管理にも役立ちます。

スマート ポインターの種類

C++ ライブラリは、次のタイプのスマート ポインターの実装を提供します。

  • auto_ptr
  • unique_ptr
  • 共有_ptr
  • 弱い_ptr

auto_ptr

auto_ptr を使用すると、新しい式から取得したオブジェクトを管理し、auto_ptr 自体が破棄されたときにオブジェクトを削除できます。 auto_ptr を介してオブジェクトが記述されると、割り当てられた単一のオブジェクトへのポインタが格納されます。

注記: このクラス テンプレートは C++11 以降非推奨になりました。 unique_ptr は、同様の機能を備えた新しい機能ですが、セキュリティが強化されています。

unique_ptr

unique_ptr 1 つのポインタのみを保存します。現在のオブジェクトをポインタから削除することで、別のオブジェクトを割り当てることができます。

C++ の一意のポインター

例:

C++




// C++ program to demonstrate the working of unique_ptr> // Here we are showing the unique_pointer is pointing to P1.> // But, then we remove P1 and assign P2 so the pointer now> // points to P2.> #include> using> namespace> std;> // Dynamic Memory management library> #include> class> Rectangle {> >int> length;> >int> breadth;> public>:> >Rectangle(>int> l,>int> b)> >{> >length = l;> >breadth = b;> >}> >int> area() {>return> length * breadth; }> };> int> main()> {> // --/ Smart Pointer> >unique_ptr P1(>new> Rectangle(10, 5));> >cout // This'll print 50 // unique_ptr P2(P1); unique_ptr P2; P2 = move(P1); // This'll print 50 cout // cout return 0; }>

>

>

出力

50 50>

共有_ptr

を使用することで 共有_ptr 複数のポインタが一度にこの 1 つのオブジェクトを指すことができ、 リファレンスカウンター を使用して use_count() 方法。

C++ の共有ポインター

C++

Javaのソートリスト




// C++ program to demonstrate the working of shared_ptr> // Here both smart pointer P1 and P2 are pointing to the> // object Addition to which they both maintain a reference> // of the object> #include> using> namespace> std;> // Dynamic Memory management library> #include> class> Rectangle {> >int> length;> >int> breadth;> public>:> >Rectangle(>int> l,>int> b)> >{> >length = l;> >breadth = b;> >}> >int> area() {>return> length * breadth; }> };> int> main()> {> >//---/ Smart Pointer> >shared_ptr P1(>new> Rectangle(10, 5));> >// This'll print 50> >cout shared_ptr P2; P2 = P1; // This'll print 50 cout // This'll now not give an error, cout // This'll also print 50 now // This'll print 2 as Reference Counter is 2 cout << P1.use_count() << endl; return 0; }>

>

>

出力

50 50 50 2>

弱い_ptr

Weak_ptr は、オブジェクトへの非所有参照を保持するスマート ポインターです。これは、shared_ptr によく似ていますが、 リファレンスカウンター 。この場合、ポインタはオブジェクトを保持しません。その理由は、ポインタがオブジェクトを保持し、他のオブジェクトを要求していると仮定すると、ポインタがオブジェクトを形成する可能性があるためです。 デッドロック。

C++ の弱いポインター

C++




// C++ program to demonstrate the working of weak_ptr> // Here both smart pointer P1 and P2 are pointing to the> // object Addition to which they both does not maintain> // a reference of the object> #include> using> namespace> std;> // Dynamic Memory management library> #include> class> Rectangle {> >int> length;> >int> breadth;> public>:> >Rectangle(>int> l,>int> b)> >{> >length = l;> >breadth = b;> >}> >int> area() {>return> length * breadth; }> };> int> main()> {> >//---/ Smart Pointer> >shared_ptr P1(>new> Rectangle(10, 5));> > >// create weak ptr> >weak_ptr P2 (P1);> > >// This'll print 50> >cout // This'll print 1 as Reference Counter is 1 cout << P1.use_count() << endl; return 0; }>

>

>

出力

50 1>

C++ ライブラリは、auto_ptr、unique_ptr、shared_ptr、weak_ptr の形式でスマート ポインターの実装を提供します。