淺拷貝:又稱值拷貝,將源對象的值拷貝到目標對象中去,本質上來講源對象和目標對象共用一份實體,只是所引用的變量名不一樣,地址其實仍是相同的。舉個簡單的例子,你的小名叫西西,大名叫鼕鼕,當別人叫你西西或者鼕鼕的時候你都會答應,這兩個名字雖然不相同,可是都指的是你。linux
假設有一個String類,String s1;String s2(s1);在進行拷貝構造的時候將對象s1裏的值所有拷貝到對象s2裏。ios
咱們如今來簡單的實現一下這個類函數
1 #include <iostream> 2 #include<cstring> 3 4 using namespace std; 5 6 class STRING 7 { 8 public: 9 STRING( const char* s = "" ) :_str( new char[strlen(s)+1] ) 10 11 { 12 strcpy_s( _str, strlen(s)+1, s ); 13 } 14 STRING( const STRING& s ) 15 { 16 _str = s._str; 17 } 18 STRING& operator=(const STRING& s) 19 { 20 if (this != &s) 21 { 22 this->_str = s._str; 23 } 24 return *this; 25 } 26 27 ~STRING() 28 { 29 cout << "~STRING" << endl; 30 if (_str) 31 { 32 delete[] _str; 33 _str = NULL; 34 } 35 } 36 37 void show() 38 { 39 cout << _str << endl; 40 } 41 private: 42 char* _str; 43 }; 44 45 int main() 46 { 47 STRING s1("hello linux"); 48 STRING s2(s1); 49 s2.show(); 50 51 return 0; 52 }
其實這個程序是存在問題的,什麼問題呢?咱們想一下,建立s2的時候程序必然會去調用拷貝構造函數,這時候拷貝構造僅僅只是完成了值拷貝,致使兩個指針指向了同一塊內存區域。隨着程序的運行結束,又去調用析構函數,先是s2去調用析構函數,釋放了它指向的內存區域,接着s1又去調用析構函數,這時候析構函數企圖釋放一塊已經被釋放的內存區域,程序將會崩潰。s1和s2的關係就是這樣的:this
進行調試程序發現s1和s2確實指向了同一塊區域:spa
因此程序會崩潰是應該的,那麼這個問題應該怎麼去解決呢?這就引出了深拷貝。.net
深拷貝,拷貝的時候先開闢出和源對象大小同樣的空間,而後將源對象裏的內容拷貝到目標對象中去,這樣兩個指針就指向了不一樣的內存位置。而且裏面的內容是同樣的,這樣不但達到了咱們想要的目的,還不會出現問題,兩個指針前後去調用析構函數,分別釋放本身所指向的位置。即爲每次增長一個指針,便申請一塊新的內存,並讓這個指針指向新的內存,深拷貝狀況下,不會出現重複釋放同一塊內存的錯誤。指針
深拷貝其實是這樣的:調試
深拷貝的拷貝構造函數和賦值運算符的重載傳統實現:code
1 STRING( const STRING& s ) 2 { 3 //_str = s._str; 4 _str = new char[strlen(s._str) + 1]; 5 strcpy_s( _str, strlen(s._str) + 1, s._str ); 6 } 7 STRING& operator=(const STRING& s) 8 { 9 if (this != &s) 10 { 11 //this->_str = s._str; 12 delete[] _str; 13 this->_str = new char[strlen(s._str) + 1]; 14 strcpy_s(this->_str, strlen(s._str) + 1, s._str); 15 } 16 return *this; 17 }
這裏的拷貝構造函數咱們很容易理解,先開闢出和源對象同樣大的內存區域,而後將須要拷貝的數據複製到目標拷貝對象,對象
那麼這裏的賦值運算符的重載是怎麼樣作的呢?
這種方法解決了咱們的指針懸掛問題,經過不斷的開空間讓不一樣的指針指向不一樣的內存,以防止同一塊內存被釋放兩次的問題,還有一種深拷貝的現代寫法:
1 STRING( const STRING& s ):_str(NULL) 2 { 3 STRING tmp(s._str);// 調用了構造函數,完成了空間的開闢以及值的拷貝 4 swap(this->_str, tmp._str); //交換tmp和目標拷貝對象所指向的內容 5 } 6 7 STRING& operator=(const STRING& s) 8 { 9 if ( this != &s )//不讓本身給本身賦值 10 { 11 STRING tmp(s._str);//調用構造函數完成空間的開闢以及賦值工做 12 swap(this->_str, tmp._str);//交換tmp和目標拷貝對象所指向的內容 13 } 14 return *this; 15 }
先來分析一下拷貝構造是怎麼實現的:
拷貝構造調用完成以後,會接着去調用析構函數來銷燬局部對象tmp,按照這種思路,不難能夠想到s2的值必定和拷貝構造裏的tmp的值同樣,指向同一塊內存區域,經過調試能夠看出來:
在拷貝構造函數裏的tmp:
調用完拷貝構造後的s2:(此時tmp被析構)
能夠看到s2的地址值和拷貝構造裏的tmp的地址值是同樣
關於賦值運算符的重載還能夠這樣來寫:
STRING& operator=(STRING s)
{
swap(_str, s._str);
return *this;
}
1 #include <iostream> 2 #include<cstring> 3 4 using namespace std; 5 6 class STRING 7 { 8 public: 9 STRING( const char* s = "" ) :_str( new char[strlen(s)+1] ) 10 11 { 12 strcpy_s( _str, strlen(s)+1, s ); 13 } 14 //STRING( const STRING& s ) 15 //{ 16 // //_str = s._str; //淺拷貝的寫法 17 // cout << "拷貝構造函數" << endl; 18 // _str = new char[strlen(s._str) + 1]; 19 // strcpy_s( _str, strlen(s._str) + 1, s._str ); 20 //} 21 //STRING& operator=(const STRING& s) 22 //{ 23 // cout << "運算符重載" << endl; 24 // if (this != &s) 25 // { 26 // //this->_str = s._str; //淺拷貝的寫法 27 // delete[] _str; 28 // this->_str = new char[strlen(s._str) + 1]; 29 // strcpy_s(this->_str, strlen(s._str) + 1, s._str); 30 // } 31 // return *this; 32 //} 33 34 STRING( const STRING& s ):_str(NULL) 35 { 36 STRING tmp(s._str);// 調用了構造函數,完成了空間的開闢以及值的拷貝 37 swap(this->_str, tmp._str); //交換tmp和目標拷貝對象所指向的內容 38 } 39 40 STRING& operator=(const STRING& s) 41 { 42 if ( this != &s )//不讓本身給本身賦值 43 { 44 STRING tmp(s._str);//調用構造函數完成空間的開闢以及賦值工做 45 swap(this->_str, tmp._str);//交換tmp和目標拷貝對象所指向的內容 46 } 47 return *this; 48 } 49 50 ~STRING() 51 { 52 cout << "~STRING" << endl; 53 if (_str) 54 { 55 delete[] _str; 56 _str = NULL; 57 } 58 } 59 60 void show() 61 { 62 cout << _str << endl; 63 } 64 private: 65 char* _str; 66 }; 67 68 int main() 69 { 70 //STRING s1("hello linux"); 71 //STRING s2(s1); 72 //STRING s2 = s1; 73 //s2.show(); 74 const char* str = "hello linux!"; 75 STRING s1(str); 76 STRING s2; 77 s2 = s1; 78 s1.show(); 79 s2.show(); 80 81 return 0; 82 }
參考與
淺析C++中的深淺拷貝 - qq_39344902的博客 - CSDN博客https://blog.csdn.net/qq_39344902/article/details/79798297