C++ 深拷贝和浅拷贝

深拷贝和浅拷贝是在C++中非常重要的概念,不管是在面试还是在未来的工作中都会经常用到,很多人在学完C++很长一段时间内可能都没有吃透什么是深拷贝和浅拷贝以及它们的运用,今天我们总结关于深浅拷贝的相关概念和底层原理:

一.浅拷贝:

首先我们来看一段代码:


#include <iostream>
#include <stdlib.h>
#include <string>
#include <assert.h>
using namespace std;
class String{
public:
	String(const char* str = " ")
		:_str(new char[strlen(str) + 1]){
		strcpy_s(_str,(strlen(str)+1), str); 
	}

	String(const String& p){
		_str=p._str;
	}
	
	~String(){
		if (_str){
			delete[] _str;
			_str = nullptr;
		}
	}

private:
	char* _str;
};

int main(){
	String* p = new String("hello world!!");
	String* p2 = new String(*p);

	delete p;
	p = nullptr;

	delete p2;
	p2 = nullptr;

	system("pause");
	return 0;
}

这个代码的执行结果是有问题的————————
在这里插入图片描述
为什么会出现这样的程序奔溃现象????-----------------我们通过调试来进行解析:
在这里插入图片描述
我们发现p和p2的地址是相同的,即p和p2共用了一个相同的地址;
String类中char* 的私有变量和拷贝构造函数中的变量同时指向一块内存块,在释放时同一块内存被多次释放导致程序奔溃,这种方式就是浅拷贝;

浅拷贝也称位拷贝,编译器只是将对象中的值拷贝过来如果对象中管理资源,最后就会导致读个对象共用同一份资源,当其中一个对象销毁时就会将该资源释放掉,而此时其他的对象不知道资源已经被释放了以为还有效,所以当继续对资源进行操作时就会发生访问违规;要解决浅拷贝问题就要通过深拷贝;

二.深拷贝:

在以上代码的基础上,我们进行调整:


#include <iostream>
#include <stdlib.h>
#include <string>
#include <assert.h>
using namespace std;
class String{
public:
	String(const char* str = " ")
		:_str(new char[strlen(str) + 1]){
		strcpy_s(_str,(strlen(str)+1), str);
		 
	}

	String(const String& p)
		:_str(new char [strlen(p._str)+1]){
		strcpy_s(_str,(strlen(p._str)+1),p._str);
	}
	
	~String(){
		if (_str){
			delete[] _str;
			_str = nullptr;
		}
	}

private:
	char* _str;
};

int main(){
	String* p = new String("hello world!!");
	String* p2 = new String(*p);

	delete p;
	p = nullptr;

	delete p2;
	p2 = nullptr;

	system("pause");
	return 0;
}

此时程序正常运行:
在这里插入图片描述
我们来看p和p2的地址:
在这里插入图片描述
这就是深拷贝的过程,每个string类对象都要用空间来存放字符串,而p2要用p拷贝构造出来;

因此,深拷贝就是给每个对象独分配资源,保证多个对象不会因为资源共享,而造成资源多次释放,导致程序奔溃;

原理:拷贝的时候先开辟出和源对象大小一样的空间,然后将源对象里的内容拷贝到目标对象中去,这样两个指针就指向了不同的内存位置。并且里面的内容是一样的,这样不但达到了我们想要的目的,还不会出现问题,两个指针先后去调用析构函数,分别释放自己所指向的位置。即为每次增加一个指针,便申请一块新的内存,并让这个指针指向新的内存,深拷贝情况下,不会出现重复释放同一块内存的错误;

设计并实现一个动态整型数组类Vect,要求: (1)实现构造函数重载,可以根据指定的元素个数动态创建初始值为0的整型数组,或根据指定的内置整型数组动态创建整型数组。 (2)设计拷贝构造函数和析构函数,注意使用深拷贝。 (3)设计存取指定位置的数组元素的公有成员函数,并进行下标越界,若越界则输出“out of boundary”。 (4)设计获取数组元素个数的公有成员函数。 (5)设计用于输出数组元素的公有成员函数,元素之间以空格分隔,最后以换行符结束。 在main函数中按以下顺序操作: (1)根据内置的静态整型数组{1,2,3,4,5}构造数组对象v1,根据输入的整型数构造数组对象v2。 (2)调用Vect的成员函数依次输出v1和v2的所有元素。 (3)输入指定的下标及对应的整型数,设置数组对象v1的指定元素。 (4)根据数组对象v1拷贝构造数组对象v3。 (5)调用Vect的成员函数依次输出v1和v3的所有元素。 设计并实现一个动态整型数组类Vect,要求: (1)实现构造函数重载,可以根据指定的元素个数动态创建初始值为0的整型数组,或根据指定的内置整型数组动态创建整型数组。 (2)设计拷贝构造函数和析构函数,注意使用深拷贝。 (3)设计存取指定位置的数组元素的公有成员函数,并进行下标越界,若越界则输出“out of boundary”。 (4)设计获取数组元素个数的公有成员函数。 (5)设计用于输出数组元素的公有成员函数,元素之间以空格分隔,最后以换行符结束。 在main函数中按以下顺序操作: (1)根据内置的静态整型数组{1,2,3,4,5}构造数组对象v1,根据输入的整型数构造数组对象v2。 (2)调用Vect的成员函数依次输出v1和v2的所有元素。 (3)输入指定的下标及对应的整型数,设置数组对象v1的指定元素。 (4)根据数组对象v1拷贝构造数组对象v3。 (5)调用Vect的成员函数依次输出v1和v3的所有元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值