C ++:浅いコピーと深いコピー

1浅いコピー

簡単な割り当てコピー操作

2ディープコピー

ヒープ領域のスペースを再申請し、コピー操作を実行します

3比較:ヒープ領域のデータを削除するかどうか

スタック領域のデータは、対応するメモリが使用された後、コンパイラによって自動的に解放されます。ヒープ領域のデータは、プログラマによって開かれ、自分で解放されます。つまり、使用後に自動的に解放されることはありません。ヒープ領域のデータを解放するのを忘れると、メモリリークが発生し、プログラム全体が実行されるまでヒープ領域のデータは再利用されません。

スタック領域のメモリを開いて変数aを格納し、ヒープ領域のメモリを開いてメンバー変数bを格納します。

エラーのデモンストレーション:ヒープ領域のデータが手動で解放されない

#include<iostream>

using namespace std;

int *g_a;
int *g_b;

void test()
{
    
    
	int a = 10;				//a存放于栈区,test函数执行完毕后,由编译器自动释放内存
	int *b = new int(20);	//b存放与堆区,test函数执行完毕后,编译器不会自动释放,需要用户自己回收 delete,否则会造成内存泄漏
	cout << "a = " << a << endl;
	cout << "b = " << *b << endl;

	g_a = &a;
	g_b = b;

	cout << "test函数执行完毕!" << endl;
}

int main()
{
    
    
	test();

	//由于栈区中的a在test函数执行完毕后自动释放,所以a对应的内存的值不为10
	cout << "a = " << *g_a << endl;
	cout << "a = " << *g_a << endl;
	cout << "a = " << *g_a << endl;

	//由于堆区中的b在test函数执行完毕后没有被释放,所以b对应的内存的值仍为20
	cout << "b = " << *g_b << endl;
	cout << "b = " << *g_b << endl;
	cout << "b = " << *g_b << endl;

	return 0;
}

出力結果:

a = 10
b = 20
test函数执行完毕!
a = -858993460
a = -858993460
a = -858993460
b = 20
b = 20
b = 20

正しいデモンストレーション:ヒープ領域のデータが使用された後、削除操作を実行します

#include<iostream>

using namespace std;

int *g_a;
int *g_b;

void test()
{
    
    
	int a = 10;				//a存放于栈区,test函数执行完毕后,由编译器自动释放内存
	int *b = new int(20);	//b存放与堆区,test函数执行完毕后,编译器不会自动释放,需要用户自己回收 delete,否则会造成内存泄漏
	cout << "a = " << a << endl;
	cout << "b = " << *b << endl;

	g_a = &a;
	g_b = b;

	delete b;	//释放堆区中的数据 b

	cout << "test函数执行完毕!" << endl;
}

int main()
{
    
    
	test();

	//由于栈区中的a在test函数执行完毕后自动释放,所以a对应的内存的值不为10
	cout << "a = " << *g_a << endl;
	cout << "a = " << *g_a << endl;
	cout << "a = " << *g_a << endl;

	//堆区中的b在test函数执行完毕后,被delete释放,所以b对应的内存的值不为20
	cout << "b = " << *g_b << endl;
	cout << "b = " << *g_b << endl;
	cout << "b = " << *g_b << endl;

	return 0;
}

出力結果:

a = 10
b = 20
test函数执行完毕!
a = -858993460
a = -858993460
a = -858993460
b = -572662307
b = -572662307
b = -572662307

4浅いコピーと深いコピー

4.1浅いコピーによって引き起こされるエラー

コード:

#include <iostream>

using namespace std;

class Person
{
    
    
public:
	Person(int age,int height)
	{
    
    
		m_age = age;
		m_height = new int (height);	//在堆区开辟一块内存,存放成员变量 m_height;需要手动释放,即需要自定义一个析构函数
		cout << "Person 有参构造函数调用" << endl;
	}
	//默认拷贝函数,如果不提供拷贝构造,编译器就会提供下面的默认拷贝函数,为浅拷贝
	Person(const Person& p)
	{
    
    
		m_age = p.m_age;
		m_height = p.m_height;	//浅拷贝,只复制p.m_height的地址,复制前后的地址指向同一块内存
		cout << "Person 默认拷贝构造函数调用" << endl;
	}

	//自定义的析构函数,用于回收堆区的数据
	~Person()
	{
    
    
		//析构,将堆区开辟的内存释放
		//如果m_height不为空指针,则释放m_height指向的内存,并将m_height赋值为空指针。
		if (m_height != NULL)
		{
    
    
			delete m_height;
			m_height = NULL;
		}

		cout << "Person 析构函数调用" << endl;
	}

	int m_age;		//年龄(存放于栈区)
	int *m_height;	//身高(存放于堆区)
};


void test()
{
    
    
	Person p1(18, 180);

	Person p2(p1);

	cout << "p1的年龄: " << p1.m_age << " 身高: " << *p1.m_height << endl;

	cout << "p2的年龄: " << p2.m_age << " 身高: " << *p2.m_height << endl;
}


int main()
{
    
    
	test();

	return 0;
}

出力結果:

Person 有参构造函数调用
Person 拷贝构造函数调用
p1的年龄: 18 身高: 180
p2的年龄: 18 身高: 180
Person 析构函数调用

操作が中断され、次のエラーが報告されます。
ここに画像の説明を挿入
それが浅いコピーの問題です!

4.2クラスメンバーがヒープ領域で開かれている場合は、浅いコピーによって引き起こされる問題を防ぐために、独自のコピーコンストラクター(ディープコピー)を提供する必要があります

コード:

#include <iostream>

using namespace std;

class Person
{
    
    
public:

	//有参构造
	Person(int age,int height)
	{
    
    
		m_age = age;
		m_height = new int (height);	//在堆区开辟一块内存,存放成员变量 m_height;需要手动释放,即需要自定义一个析构函数
		cout << "Person 有参构造函数调用" << endl;
	}

	//自定义的拷贝构造函数
	Person(const Person& p)
	{
    
    
		m_age = p.m_age;
		m_height = new int(*p.m_height);	//深拷贝,重新在堆区开辟一块内存存放拷贝后的数据
		cout << "Person (自定义)拷贝构造函数调用" << endl;
	}
	
	//自定义的析构函数,用于回收堆区的数据
	~Person()
	{
    
    
		//析构,将堆区开辟的内存释放
		//如果m_height不为空指针,则释放m_height指向的内存,并将m_height赋值为空指针。
		if (m_height != NULL)
		{
    
    
			delete m_height;
			m_height = NULL;
		}

		cout << "Person 析构函数调用" << endl;
	}

	int m_age;		//年龄(存放于栈区)
	int *m_height;	//身高(存放于堆区)
};


void test()
{
    
    
	Person p1(18, 180);

	Person p2(p1);

	cout << "p1的年龄: " << p1.m_age << " 身高: " << *p1.m_height << endl;

	cout << "p2的年龄: " << p2.m_age << " 身高: " << *p2.m_height << endl;
}


int main()
{
    
    
	test();

	return 0;
}

出力結果:

Person 有参构造函数调用
Person (自定义)拷贝构造函数调用
p1的年龄: 18 身高: 180
p2的年龄: 18 身高: 180
Person 析构函数调用
Person 析构函数调用

4.3浅いコピーと深いコピーの図

浅いコピーはアドレスをコピーするだけです。コピーの前後の2つのアドレスは同じメモリを指します。p1がデストラクタを呼び出すと、メモリスペースはすぐに解放されます。p2がデストラクタを呼び出すと、解放するメモリはありません。そのため、エラーが発生します。
ここに画像の説明を挿入
ディープコピー。ヒープ領域のメモリを開いて、コピーしたデータを保存します。これにより、デストラクタを呼び出すときにp1とp2が互いに干渉しなくなります。
ここに画像の説明を挿入

それでもわからない場合は、https://www.bilibili.com/video/BV1et411b73Z?p=110を参照してください。

おすすめ

転載: blog.csdn.net/weixin_46098577/article/details/122179878