淺拷貝:以string類爲例 當對一個已知對象進行拷貝時,編譯系統會自動調用一種構造函數 —— 拷貝構造函數,若是用戶未定義拷貝構造函數,則會調用默認拷貝構造函數。默認拷貝構造屬於淺拷貝,至關於兩個指針變量指向了同一塊地址空間,調用析構函數時,會delete兩次,因此在第二次delete時會發生中斷(沒法尋址地址)c++
//淺拷貝 class string { private: char* _str; public: string(char* str = "")//構造函數 { if (nullptr == str) { str = ""; } _str = new char[strlen(str) + 1]; strcpy(_str,str); } string(const string& s)//拷貝構造 :_str(s._str) { } string operator =(string& s)//賦值構造 { _str = s._str; return *this; } ~string() { if (_str) { delete _str; _str = nullptr; } } };
解決方案1.傳統深拷貝
在拷貝構造中從新開闢空間,而後把被拷貝對象中的元素拷貝到新空間中ide
//缺點:須要屢次開闢空間,代碼冗餘 //優勢:可讀性高 class string { private: char* _str; public: string(char* str = "") { if (str == nullptr) { str = ""; } _str = new char[strlen(str) + 1]; strcpy(_str,str); } string(const string& s) :_str(new char[strlen(s._str)+1]) { strcpy(_str,s._str); } string& operator=(string& s) { if (this != &s) { char* temp = new char[strlen(s._str) + 1]; strcpy(temp,s._str); delete _str; _str = temp; } return *this; } ~string() { if (_str) { delete _str; _str = nullptr; } } };
解決方案2.精簡深拷貝
1.傳址,在方法中從新定義一個對象接受被拷貝對象元素,而後交換臨時對象和須要拷貝對象的地址
2.傳值,直接交換臨時對象和須要拷貝對象的地址函數
//優勢:代碼高效 缺點:可讀性不高 class string { private: char* _str; public: string(char* str="") { if (str == nullptr) { str = ""; } _str = new char[strlen(str) + 1]; strcpy(_str,str); } string(const string& s) :_str(nullptr) { string temp(s._str); swap(_str,temp._str); } /*string& operator=(const string& s) { if (this != &s) { string temp = s._str; swap(_str,temp._str); } return *this; }*/ string& operator=(string s)//直接改變指向(傳值:臨時變量) { swap(_str,s._str); return *this; } ~string() { if (_str) { delete[] _str; _str = nullptr; } } };
解決方案3.淺拷貝+計數(至關於出門時,最後一我的才「關門」,進出門的人進行計數)
計數:定義一個成員_count,在普通構造函數中直接初始化爲1,而進行拷貝構造時判斷被拷貝對象的成員_count++,而須要拷貝對象的成員_count是否爲0,(若是爲0,則須要拷貝對象成員_count++,若是>0,則則須要拷貝對象成員_count--),最後析構函數中對象_count成員爲0時,調用deletethis
class string { private : char* _str; int* _count; public : string(char* str="") : _count(new int(1))//調用普通構造:_count初始化爲1 , _str(new char[strlen(str) + 1]) { if (str == nullptr) { str = ""; } strcpy(_str,str); } string(const string& s) :_str(s._str) , _count(s._count) { ++(*_count); } string operator=(string& s) { if (this != &s) { if (0 == --(*_count)) { delete[] _str; delete _count; _str = nullptr; _count = nullptr; } _str = s._str; _count = s._count; ++(*_count); } return *this; } ~string() { if (_str&&0 == --(*_count)) { delete[] _str; delete _count; _str = nullptr; _count = nullptr; } } char& operator[](size_t index) { if ((*_count) > 1) { string temp(_str); this->swap(temp); } return _str[index]; } void swap(string& s) { std::swap(_str,s._str); std::swap(_count,s._count); } const char& operator[](size_t index)const { return _str[index]; } };