Shallow copy: take string class as an example
When copying a known object, the compiler will automatically call a constructor - copy constructor. If the user does not define a copy constructor, the default copy constructor will be called. The default copy structure belongs to the shallow copy, which is equivalent to two pointer variables pointing to the same address space. When the destructor is called, it will delete twice, so the second delete will break (address cannot be addressed).
//Shallow copy class string { private: char* _str; public: string(char* str = "")//Constructor { if (nullptr == str) { str = ""; } _str = new char[strlen(str) + 1]; strcpy(_str,str); } string(const string& s)//copy construction :_str(s._str) { } string operator =(string& s)//Assignment structure { _str = s._str; return *this; } ~string() { if (_str) { delete _str; _str = nullptr; } } };
Solution 1. Traditional deep copy
//Disadvantages: need to open up space many times, code redundancy //Advantages: high readability 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; } } };
Solution 2.
//Advantages: code efficiency disadvantages: low readability 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)//Direct change of direction (pass value: temporary variable) { swap(_str,s._str); return *this; } ~string() { if (_str) { delete[] _str; _str = nullptr; } } };
Solution 3. Shallow Copy + count
class string { private : char* _str; int* _count; public : string(char* str="") : _count(new int(1))//Call normal construct: "count is initialized to 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]; } };