计算机系统应用教程网站

网站首页 > 技术文章 正文

C++深入理解浅拷贝和深拷贝,码了一年才懂

btikc 2024-09-12 12:07:53 技术文章 21 ℃ 0 评论

关于对象的拷贝,大部分时间我们用的都是浅拷贝,比如赋值符号(“=”)以及memcpy()等。那么既然浅拷贝这么简单,为什么还需要深拷贝呢?两者之间的区别又是什么呢?两者分别在什么情况下使用呢?

可能很多人写了很久的代码,都还只知道对象赋值而不知道深拷贝,导致很多时间出现莫名bug而且找不到原因。今天就让我们深入的来了解一下两者的区别。

浅拷贝

例如:

class MyClass
{
public:
	MyClass(int x);
	~MyClass();
	int a ;
private:
};
MyClass::MyClass(int x)
{
	this->a = x ;
}
MyClass::~MyClass()
{
}
void main()
{	
	int b = 100 ;//浅拷贝
	MyClass my1(10) ;
	MyClass my2 = my1;//浅拷贝
	MyClass my3(20) ;
	memcpy(&my3,&my1,sizeof(MyClass));//浅拷贝
	cout<<"my1.a:"<<my1.a<<endl;
	cout<<"my2.a:"<<my2.a<<endl;
	cout<<"my3.a:"<<my3.a<<endl;
	system("pause");
}

运行结果是都是10,以上三个都是浅拷贝,浅拷贝的原理就是:将 被拷贝对象所在内存中的数据按照二进制位(Bit)复制到新对象所在的内存,这种默认的拷贝行为就是浅拷贝。其原理图如下:

浅拷贝的缺点

上面的例子中,MyClass都是基本类型,这种浅拷贝用起来是没有什么问题,但是C++的难点是什么?对,就是指针。如果MyClass成员中有指针类型怎么办?是不是也用浅拷贝呢?

我们在Mycalss类中新增一个char* str 成员,还是按上面那样用浅拷贝的方式拷贝对象。

class MyClass
{
public:
	MyClass(int x,char * s);
	~MyClass();
	int len;
	int a ;
	char* str ;
private:
};
MyClass::MyClass(int x,char* s ,int length)
{
//这里注意不能直接this->str = s ;因为指向的是常量,常量内存我们是delete不了的
	this->len = lenth ;
	this->a = x ;
	this->str = new char[this->len] ;
	memcpy(str,s,this->len);
}
MyClass::~MyClass()
{
}
void main()
{	
	int b = 100 ;//浅拷贝
	MyClass my1(10,"i love u") ;
	MyClass my2 = my1;//浅拷贝
	MyClass my3(20,"i do not love u") ;
	memcpy(&my3,&my1,sizeof(MyClass));
	cout<<"my1.a:"<<my1.a<<endl;
	cout<<"my2.a:"<<my2.a<<endl;
	cout<<"my3.a:"<<my3.a<<endl;
	cout<<"my1.str:"<<my1.str<<endl;
	cout<<"my2.str:"<<my2.str<<endl;
	cout<<"my3.str:"<<my3.str<<endl;
	system("pause");
}
运行起来好像没有什么问题;但是如果当我在my1通过my1的str指针将str指向的内存delete掉会发生什么?
cout<<"my1.str:"<<my1.str<<endl;
delete[] my1.str;
cout<<"delete OK"<<endl;
cout<<"my2.str:"<<my2.str<<endl;
cout<<"my3.str:"<<my3.str<<endl;

我们发现my2.str和my3.str打印出来的是一堆乱码。这是为什么呢?请看下面的示意图:

浅拷贝复制的只是指针变量,但是这个指针所管理的内存还是my1的。所以当你通过my1删除了str所管理的内存,那么在my2和my3中的str就找不到这块内存原来的内容了;

深拷贝的实现

既然浅拷贝在对象中存在着管理其他内存的指针时,在对象的内存释放时会出现野指针的问题,那么如何去避免呢?很简单,除了会将原有对象的所有成员变量拷贝给新对象,还会为新对象再分配一块内存,并将原有对象所持有的内存也拷贝过来。

实现代码:

#include <stdio.h>
#include <string>
#include <iostream>
#include <complex>
using namespace std;
class MyClass
{
public:
	MyClass(int x,char * s,int len);
	MyClass(const MyClass& myclass);
	~MyClass();
	int len ;
	int a ;
	char* str;
private:
};
MyClass::MyClass(int x, char* s,int length)
{
	this->len = length ;
	this->a = x ;
	this->str = new char[this->len] ;
	memcpy(str,s,this->len);
}
MyClass::MyClass(const MyClass& myclass)
{
	this->len = myclass.len ;
	this->a = myclass.a ;
	this->str = new char[this->len] ;
	memcpy(this->str,myclass.str,this->len);
}
MyClass::~MyClass()
{
}
void main()
{	
	cout<<sizeof(char)<<endl;
	int b = 100 ;//浅拷贝
	MyClass my1(10,"i love u",6) ;
	MyClass my2 = my1;//浅拷贝
	MyClass my3(20,"i do not love u",15) ;
	memcpy(&my3,&my1,sizeof(MyClass));
	cout<<"my1.a:"<<my1.a<<endl;
	cout<<"my2.a:"<<my2.a<<endl;
	cout<<"my3.a:"<<my3.a<<endl;
	cout<<"my1.str:"<<my1.str<<endl;
	delete[] my1.str;
	cout<<"delete OK"<<endl;
	cout<<"my2.str:"<<my2.str<<endl;
	cout<<"my3.str:"<<my3.str<<endl;
	system("pause");
}

但是memcpy()方法是没法使用深拷贝的,因为它是直接操作在内存上的;

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表