浅拷贝:以string类为例 c++浅拷贝以及浅拷贝的解决方案 当对一个已知对象进行拷贝时,编译系统会自动调用一种构造函数 —— 拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数。默认拷贝构造属于浅拷贝,相当于两个指针变量指向了同一块地址空间,调用析构函数时,会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;
}
}
};
c++浅拷贝以及浅拷贝的解决方案 解决方案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];
}
};