C++: copia superficial frente a copia profunda

1 copia superficial

Operación de copia de asignación simple

2 copia profunda

Vuelva a solicitar espacio en el área de montón y realice una operación de copia

3 Comparación: si eliminar los datos en el área del montón

El compilador libera automáticamente los datos en el área de la pila después de que se usa la memoria correspondiente; el programador abre los datos en el área del montón y los libera él mismo, es decir, no se liberarán automáticamente después de su uso. Si olvida liberar los datos en el área del montón, se producirá una pérdida de memoria y los datos del área del montón no se recuperarán hasta que se ejecute todo el programa.

Abra una parte de la memoria en el área de la pila para almacenar la variable a; abra una parte de la memoria en el área del montón para almacenar la variable miembro b.

Demostración de error: los datos en el área del montón no se liberan manualmente

#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;
}

Resultado de salida:

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

Demostración correcta: después de usar los datos en el área del montón, ejecute la operación de eliminación

#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;
}

Resultado de salida:

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

4 Copia superficial y copia profunda

4.1 Errores causados ​​por copia superficial

Código:

#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;
}

Resultado de salida:

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

La operación se interrumpe y se informa el siguiente error.
inserte la descripción de la imagen aquí
¡Ese es el problema con las copias superficiales!

4.2 Si los miembros de la clase se abren en el área del montón, debe proporcionar su propio constructor de copias (copia profunda) para evitar problemas causados ​​por copias superficiales

Código:

#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;
}

Resultado de salida:

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

4.3 Diagrama de copia superficial y copia profunda

La copia superficial solo copia la dirección. Las dos direcciones antes y después de la copia apuntan a la misma pieza de memoria. Cuando p1 llama al destructor, el espacio de memoria se liberará inmediatamente; cuando p2 llama al destructor, no hay memoria para liberar. por lo que se produce un error.
inserte la descripción de la imagen aquí
Copia profunda, abra una parte de la memoria en el área del montón para almacenar los datos copiados, de modo que p1 y p2 no interfieran entre sí cuando llamen al destructor.
inserte la descripción de la imagen aquí

Si aún no lo entiende, consulte https://www.bilibili.com/video/BV1et411b73Z?p=110

Supongo que te gusta

Origin blog.csdn.net/weixin_46098577/article/details/122179878
Recomendado
Clasificación