c++浅拷贝以及浅拷贝的解决方案
浅拷贝:以string类为例
当对一个已知对象进行拷贝时,编译系统会自动调用一种构造函数 —— 拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数。默认拷贝构造属于浅拷贝,相当于两个指针变量指向了同一块地址空间,调用析构函数时,会delete两次,所以在第二次delete时会发生中断(无法寻址地址)
//浅拷贝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.传统深拷贝
在拷贝构造中重新开辟空间,然后把被拷贝对象中的元素拷贝到新空间中
//缺点:需要多次开辟空间,代码冗余//优点:可读性高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时,调用delete
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]; } };
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。