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->() {>> |