C++中的深拷贝和浅拷贝

概念

浅拷贝指的是复制对象的时候,对对象中的数据成员进行赋值操作,完成成员的复制,有点类似于函数中的值传递,系统的默认构造函数执行的也是浅拷贝。

而深拷贝是对对象中的成员除了赋值操作之外,还会重新动态申请内存空间来存储该数据。所以,如果我们没有重写拷贝构造函数时,系统会创建默认拷贝构造函数,此时的拷贝则都是浅拷贝。


浅拷贝的问题

我们大多数人写类的时候应该很少会去重写拷贝构造函数,这在类的数据成员中没有指针时,当然是可行的,但一旦数据成员中有指针,那么问题就出现了。此时调用浅拷贝(即系统创建的默认拷贝构造函数)会使新对象的指针指向的地址与被拷贝对象的指针指向的地址相同,即两者指向了同一段内存空间,那么当这两个对象被释放时就会调用两次析构函数去delete相同的内存空间而产生错误,所以此时就需要用到深拷贝了。


如何解决

深拷贝与浅拷贝的区别就在进行数据复制时会申请一块新的内存空间去存储数据,当遇到数据成员存在指针时,完美的避免了重复析构同一段内存空间的问题。当然,如果数据成员中没有指针的话即可不必写深拷贝了,毕竟重新申请内存空间会影响效率和性能。


例子

写一个学生类,其中包含属性为学生的名字指针,学生的id及学生的id指针,写出此类的构造,拷贝构造和析构函数的声明。

class Student
{
public:
	//char name[128];
	char* name;
	long id;
	long* pid;
public:
	// 构造函数
	Student(const char* name, long id);
	// 拷贝构造
	Student(const Student& other);
	// 析构函数
	~Student();
};

现在将类中的构造函数,拷贝构造函数及析构函数都实现一下。在实现拷贝构造函数时,我们可以去试一下浅拷贝和深拷贝的区别,比如学生的姓名指针,浅拷贝的写法就是使用this和other指针直接赋值,而深拷贝则是重新申请了一段内存空间,去存储复制过来的学生姓名。

Student::Student(const char* name, long id)
{
	this->name = new char[128];
	strcpy(this->name, name);
	this->id = id;
	this->pid = &this->id;
}
Student::Student(const Student& other)
{
	//浅拷贝
	this->name = other.name;
	//深拷贝/位拷贝
	this->name = new char[128];
	strcpy(this->name, other.name);
	this->id = other.id;
	// 浅拷贝
	this->pid = other.pid;
	//深拷贝
	this->pid = &this->id;
}
Student::~Student()
{
	delete name;
	name = nullptr;
}

完整代码如下:

#include <iostream>
using namespace std;

class Student
{
public:
	//char name[128];
	char* name;
	long id;
	long* pid;
public:
	// 构造函数
	Student(const char* name, long id);
	// 拷贝构造
	Student(const Student& other);
	// 析构函数
	~Student();
};
Student::Student(const char* name, long id)
{
	this->name = new char[128];
	strcpy(this->name, name);
	this->id = id;
	this->pid = &this->id;
}
Student::Student(const Student& other)
{
	//浅拷贝
	//this->name = other.name;
	//深拷贝/位拷贝
	this->name = new char[128];
	strcpy(this->name, other.name);
	this->id = other.id;
	// 浅拷贝
	//this->pid = other.pid;
	//深拷贝
	this->pid = &this->id;
}
Student::~Student()
{
	delete name;
	name = nullptr;
}
// 打印学生信息
void printStudentInfo(Student* ps)
{
	cout << "姓名:" << ps->name << 
		",学号:" << *ps->pid << endl;
}
int main()
{
	Student s1("张三", 1001);
	Student s2(s1);
	s1.id = 10086;
	printStudentInfo(&s1);
	printStudentInfo(&s2);

	return 0;
}

总结

大部分时候浅拷贝可以满足我们的需求,但是一旦类中的数据成员有指针或者拷贝的对象有对其他资源的引用时,我们最好重写拷贝构造函数为深拷贝。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值