關于對象的拷貝,大部分時間我們用的都是淺拷貝,比如賦值符号(“=”)以及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()方法是沒法使用深拷貝的,因為它是直接操作在内存上的;
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!