浅いコピーと深いコピー
前のセクションで説明したコピー コンストラクターの例である Circle クラスでは、コピー戦略はシステムのデフォルト戦略と一致しています。つまり、元のオブジェクトのメンバーが新しいオブジェクトの対応するメンバーに順番にコピーされます。この場合、なぜ自分で定義しますか?その理由は、この単純な方法ですべての状況を初期化するだけでは、必然的にさまざまな状況で問題が発生するためです。
たとえば、先ほどの Circle クラスで、メンバー変数にポインター メンバーが追加され、初期化中にメモリを動的に割り当てる必要がある場合、セキュリティ上の大きなリスクが発生します。コードは次のとおりです。
/*************************************//Des: C++ チュートリアル支援プログラム//作者 :Huang //コピーライト:www.dotcpp.com//日付:2017/8/26***************************** ** ******/#include<iostream>#include<Cstring>usingnamespacestd;#definePI3.1415classCircle{private:doubleR;char*str;public:Circle(doubleR,char*str);~Doublearea() );doublegirth();};Circle::~Circle(){delete[]str;}Circle::Circle(doubleR,char*str){cout<<Constructor<<endl;this->R=R ;this ->str=newchar[strlen(str)+1];strcpy(this->str,str);cout<<this->R<<<<this->str<<endl;}doubleCircle::area () {returnPI*R*R;}doubleCircle::girth(){return2*PI*R;}intmain(){CircleA(5,NO.1Oldclass);CircleB(A);return0;}
検証するために、Circle クラスにポインター メンバーを追加し、カスタム コピー コンストラクターを使用せずにコンストラクター内でそれを初期化しました。次に、main 関数で、Circle B(A); という文が A オブジェクトを B オブジェクトに割り当て、実行後に、プログラムは次のようにエラーを報告します。
実際の理由は、デフォルトのコピー コンストラクターはデータの割り当てのみを実行し、ポインター用のメモリ領域を開くことができないためです。これは次のコードに相当します。
これ->str=str;
したがって、本質的には、2 つのポインターがヒープ領域の一部を指します。それは私たちの当初の意図に反してしまいました。次に、プログラムの最後で 2 つのオブジェクトがリサイクルされるときに、このメモリ領域を解放するために独自のデストラクターが呼び出されます。2 つのオブジェクトは 2 回呼び出す必要があるため、つまり 2 回削除する必要があるため、エラーが発生します。
したがって、クラスにポインター型がある場合、デフォルトのコピー コンストラクター メソッドに依存することはできなくなり、データをコピーするだけでなく、メンバーにメモリ領域を割り当てることもできる特定のコピー コンストラクターを定義する必要があります。実際のコピー (ディープ コピーとも呼ばれます) を実現するには、これがディープ コピー コンストラクターです。
ディープコピーコンストラクターの実装:
#include<iostream>#include<Cstring>usingnamespacestd;#definePI3.1415classCircle{private:doubleR;char*str;public:Circle(doubleR,char*str);Circle(Circle&A);~Circle();doublerea(); doublegirth();};Circle::~Circle(){delete[]str;cout<<CallDestructor<<endl;}Circle::Circle(Circle&A){cout<<CopyConstructor<<endl;this->R=AR ;this->str=newchar[strlen(A.str)+1];strcpy(this->str,A.str);}Circle::Circle(doubleR,char*str){cout<<コンストラクター<<endl ;this->R=R;this->str=newchar[strlen(str)+1];strcpy(this->str,str);}doubleCircle::area(){returnPI*R*R;}doubleCircle: :girth(){return2*PI*R;}intmain(){CircleA(5,NO.1Oldclass);CircleB(A);return0;}
実装原理は、パラメータを使用したコンストラクタと同様で、完全なコピーを完全に完成させるために、割り当て前に十分なメモリ領域が開かれます。理解してパソコンで試してみてください!