【C++ベースの4】深いコピーと浅いコピー


1.通常型オブジェクトのコピー
通常のタイプのオブジェクトのコピーは簡単で、値のコピーです.例:
int _tmain(int argc, _TCHAR* argv[])
{
	int a=1;
	int b=a;
	return 0;
}

2.クラスオブジェクトのコピー
クラスオブジェクトのコピーは、通常のタイプのコピーよりも複雑で、さまざまなメンバー変数が存在します.例:
CopyTest.h
class CCopyTest
{
public:
	CCopyTest(int _size):size(_size){}
	~CCopyTest(void){}

private:
	int size;
};
main.cpp
int _tmain(int argc, _TCHAR* argv[])
{
	CCopyTest a(3),b=a;
	return 0;
}

プログラムは正常に動作し、b.size=3で、普通のタイプのデータと悪くないように見えます.よし、下を見続けよう.
3.浅いコピー
もう一つの例を見てみましょう.
main.cppは上と同じですhを以下に変更する.
class CCopyTest
{
public:
	CCopyTest(int _size):size(_size){data=new int[size];}
	~CCopyTest(void){delete []data;}//          

private:
	int size;
	int* data;
};

このとき、実行検出プログラムが停止したり、クラッシュしたり、応答しなかったりします.どうしてですか.
理由:
この時、浅いコピーの概念が出てきました.あるオブジェクトを別のオブジェクトに割り当てる場合、上記の例のように、データメンバー間の値の単純なコピーだけを行う場合、b.size=a.size;b.data=a.data.注意、dataはポインタですね.では、a.dataとb.dataは同じメモリ空間を指します.オブジェクトaがフィクションの場合、a.dataが指すスタックメモリが解放される.この場合、オブジェクトbの番になってフィクションが行われ、b.dataが指すスタックメモリが再び解放されるように要求されると、問題が発生する.
一方,例2に異常がないのは,CopyTestというクラスにはポインタなど他のリソースを参照するオブジェクトがないため,この場合の浅いコピーと深いコピーは区別されないからである.
4.深いコピー
深いコピーとは、コピー・オブジェクトにヒープ、ファイル、システムなどの他のリソースへの参照がある場合(参照はポインタまたは参照であってもよい)に、コピー・オブジェクトに他のリソースへの参照があるポインタまたは参照を単純に割り当てずに、コピー・オブジェクトに新しいリソースを開き、コピー・オブジェクトに他のリソースへの参照があるポインタまたは参照を同期させることです.
私たちは上の例を直します.
main.cppは変わらないh変更先:
class CCopyTest
{
public:
	CCopyTest(int _size):size(_size){data=new int[size];}
	~CCopyTest(void){delete []data;}

	CCopyTest(const CCopyTest& _copy):size(_copy.size){data=new int[size];memcpy(data,_copy.data,size);}//         

private:
	int size;
	int* data;
};

ここで、コピーコンストラクタは、値コンストラクタ自体が値コピーを行うため、コピーコンストラクタを呼び出すと無限ループネストを引き起こし、コンパイラがエラーを報告し、スタックがオーバーフローするため、参照コンストラクタを使用する必要があります.VSもGCCも間違えます.
5.まとめ
要するに、オブジェクトのコピーを行う場合、オブジェクトに他のリソースへの参照が含まれている場合、そのオブジェクトが参照しているオブジェクトをコピーする必要がある場合は、深いコピーであり、そうでなければ浅いコピーである.