1.はじめに
https://www.cnblogs.com/zhaoyixiang/p/12116203.html深い浅いコピーの最後のポストは、コピー
、我々は手がそのCかどうか、メモリリークがとき浅いコピーを発生する可能性がありますコピーして、我々がターゲットにあったことを知った++それはの導入と同様に、パイソン、JAVAのように達成することができ
、ガベージコレクションメカニズムメモリを管理するための柔軟性を。
残念ながら、C ++は、このようにC ++動的に得られ、ガベージコレクション(Gabageコレクタ)でのPython、Javaや他のプログラミング言語好きではない
プログラマーと呼ばれる悪夢ストレージ管理、懸濁記憶喪失(メモリリーク)がありましたポインタ、ポインタの不正アクセスの問題。
私はBjarneを考える:
「私は意図的にこれは自分自身の経験のガベージコレクションシステムに基づいています(通常、そのガベージコレクションを指示し)、それは自動ガベージコレクションに頼らない、C ++を設計しました。
私は深刻な空間と時間のオーバーヘッドその怖いです、またによるガベージコレクションシステムによって引き起こさ実装と移行の複雑さの恐怖に。また、ガベージコレクション意志+ C
+は、基礎となる作業の多くは適していませんが、これはまさにその設計目標の一つである。しかし、私のガベージコレクションのようなアイデア、それは、設計を簡素化することができますメカニズムで
エラーの根本原因の多くを除外しています。
C ++のコンストラクタとデストラクタが.Bjarneは有名な格言、「リソースの需要があるがあったリソースを自動的に解放する必要性を解決するために設けられています初期化(リソースInquirmentが初期化される)」。
したがって、我々は、リソースを移動することができるアプリケーションを割り当てる必要がコンストラクタに完成し、すでにデストラクタで割り当てられたリソースを解放します。されて
C ++で、それはあなたのコントロールオブジェクトを作成することができます、はっきりと、我々はこの制御を実現するために呼び出され、参照カウントのガベージコレクションを開発することができますコピー
2.デザインのアイデア
まず、デストラクタポインタオブジェクトは(ホッ)を削除する必要があるときに我々は、オブジェクト構造体ポインタの存在下で定義しますが、この時点で我々は、オブジェクト、新しい無い新しいポインタのシャローコピーした場合。
:オブジェクト(ポインタメモリが二度明確な条件をリリースしている)、私たちは参照カウントを通じて、この問題を解決するために使用された場合、デストラクタのメモリリークが発生した
各構築物、新しいカウンタと1それぞれを作成します。コピーそのオブジェクトが+1コピーされるカウンタで構成回;
デストラクタ場合(スタックと同様最初の放電後組み込み、)順序デストラクタにコンストラクタ、最後の構成やコピーを解放するために、
最初のリリースの各-1カウンターと(オブジェクトの浅いコピーがある場合)、カウンタが0であるか否かを判断するが、0よりも大きい場合、配列は、オブジェクトのデストラクタデストラクタに従って続け、
カウンタが0である場合、ポインタは解放されます。
3.例
我々は、第1及び第3のオブジェクトの浅い二回コピーし、カウンタが基準2、3と呼ばれるために3つのオブジェクトを構築し
、それぞれ、オブジェクト212の1,2,3-完全なコピーした後にカウンタの値を。
第1のカウンタ3のリリース後デストラクタオブジェクトのうち、カウンタ-1に等しいです。カウンタ211
のカウンタ1の再販後はデストラクタオブジェクトのうち、カウンタ-1に等しいです。111のカウンタ
リリースカウンタカウンタ3の後には、-1オブジェクトオフデストラクタ0に等しく、ポインタを解放します。カウンタ11は空である
と、カウンタ2の後にカウンタを解放すると、-1オブジェクトオフデストラクタ0に等しく、ポインタを解放します。1つの空白空白カウンタ
カウンタ1の後には、その後、-1オブジェクトオフデストラクタを0に等しく、ポインタを解放カウンタ放出します。ヌルヌルヌルカウンタ
のすべてのオブジェクトの最終的な破壊が完了すると、ポインタはすべて既にリリースされています
4.コード
//クラス参照カウント クラスCRefCount { 公衆: CRefCount(); //カウンタ・オブジェクト構造 CRefCount(定数CRefCount&OBJ); //コピーカウンタ設定さ void *型のAlloc(int型のサイズ); //オブジェクト・スペース・アプリケーションを構築します int型のAddRef(); //カウントがインクリメントされ int型ReleaseRef(); //カウントが減少しました 〜CRefCount(); 民間: void *型m_pBuf;バッファへのポインタ// int型* m_pRefCount; //数 }。 CRefCount :: CRefCount() { m_pBuf = nullptr; m_pRefCount = nullptr; } CRefCount :: CRefCount(のconst CRefCount&OBJ) { m_pBuf = obj.m_pBuf。 m_pRefCount = obj.m_pRefCount。 AddRef(); } void *型CRefCount ::のAlloc(int型のサイズ) { m_pBuf =新しい文字[サイズ+ 1]; //アプリケーションバッファ m_pRefCountは新しいINT(0)=。 AddRef(); //オブジェクトが構築されるたびにカウント+ m_pBufを返します。 } int型CRefCount ::のAddRef() { もし(m_pRefCount == nullptr) 0を返します。 リターン++(* m_pRefCount)。 } int型CRefCount :: ReleaseRef() { もし(m_pRefCount == nullptr) 0を返します。 リターン - (* m_pRefCount)。 } CRefCount ::〜CRefCount() { (ReleaseRef()== 0)の場合 { もし(m_pBuf!= nullptr) { [] m_pBufを削除します。 m_pBuf = nullptr; m_pRefCountを削除します。 m_pRefCount = nullptr; } } }
5.テスト
//学生のテスト #include "CRefCount.h" 書式#include <iostreamの> #pragma警告(無効:4996) 名前空間stdを使用。 クラスCStudent { 民間: char * m_pName。 CRefCount m_RefCount; constのchar *項目GetName()constは、 公衆: CStudent(のconstのchar *はpName)。 }。 constのchar * CStudent ::関連項目GetName()constは { m_pNameを返します。 } CStudent :: CStudent(のconstのchar *はpName) { m_pName =(CHAR *)m_RefCount.Alloc(STRLEN(はpName)+ 1); //の名前のための記憶空間を適用します strcpyの(m_pName、はpName)。 } メインint型() { CStudent S1( "影"); CStudent S2( "iceice"); CStudent S3( "たぶん"); CStudent S4 = S1; CStudent S5 = S3; 0を返します。 }
工事完了後、アプリケーションをデバッグし、我々はメモリビューをコピーして、1,2,3 2,1,2に対応する、この時間カウンタ値で見ることができます
2,1,1のように図1に示すように、3つのカウンタの値 - シングルステップと、オブジェクト構造の最初のコピーがデストラクタオフであり、カウンタ値を参照してください
後方に行くし続け、ポインタオフ第二メモリコピー対象のデストラクタカットは、カウンタ、1-1で解放されていない見つけたときのカウンタ値1,1,1
後に再び第三の構成のオブジェクトは、オブジェクト・ポインタ3が解除され、カウンタが0に達しつつオフ破壊が開始されており、行います。
プラス補助デバッグコードは、あなたが2、3がリリースされたコピーは、構造体3の最終結果を見ることができ、完成参照カウント機能