关于对象的拷贝,大部分时间我们用的都是浅拷贝,比如赋值符号(“=”)以及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()方法是没法使用深拷贝的,因为它是直接操作在内存上的;
,