版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39412582/article/details/81515037
上篇博客我们说浅拷贝存在同一块资源被多次释放的问题,那么这篇博客就是给浅拷贝擦屁股,解决它遗留下来的问题。
解决这个问题,我们可以考虑单独给 s2 开辟一块空间,只将 s1 里的内容拷贝到 s2。
看一看我们代码是怎么实现的吧:
class String
{
public:
String(const char* pStr = "")
{
if (NULL == pStr) //保证这个字符串里面至少有一个大小的空间
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
//如果该字符串不空,重新开辟一块空间,将原来字符串里的内容拷贝到新空间中
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
//普通版版本
String(const String& s) //拷贝构造函数,这里没有判断字符串是否为空,是因为它不可能为空
:_pStr(new char[strlen(s._pStr) + 1])
{
strcpy(_pStr, s._pStr);
}
//要做到赋值运算符重载,首先当然是开辟一块新空间来保存待拷贝的内容,然后将旧空间元素拷贝到新空间,紧接着释放掉旧空间,指向新空间,这样复制拷贝整个过程就结束了
String& operator=(const String& s)
{
if (this != &s) //首先判断是不是自己给自己赋值
{
//法一:如果内存开辟失败不会影响原来的空间
char* pTemp = new char[strlen(s._pStr) + 1]; //申请新空间
strcpy(s._pStr, _pStr); //拷贝元素
delete[] _pStr; //释放旧空间
_pStr = pTemp; //使用新空间
//法二:上来就释放就空间,倘若新空间开辟失败会影响原来的空间
delete[] _pStr;
_pStr = new char[strlen(s._pStr) + 1];
strcpy(_pStr, s._pStr);
}
return *this;
}
~String()
{
if (_pStr)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
};
void TestFunc()
{
String s1("hello");
String s2(s1);
String s3;
s3 = s1;
}
int main()
{
TestFunc();
return 0;
}
我们来看看结果怎么样:
除了函数作用域,调用析构函数,里面内容全部被清空,没有问题对不对。
那有人就会问有没有更简单的方法来实现这个功能呢?当然有了
这次我给出一个简洁版的代码:
//第一种
String& operator=(const String& s)
{
if (this != &s)
{
//既然要拷贝元素,那我直接给一个String类调用拷贝构造函数,然后在进行交换那岂不是万事大吉,代码很简洁,还不会出错
String strTemp(s._pStr);
swap(_pStr, strTemp._pStr);
}
return *this;
//第二种
String& operator=(const String& s)
{
String strTemp(s);
swap(_pStr, strTemp._pStr);
return *this;
}
//第三种
String& operator=(String s)
{
swap(_pStr, s._pStr);
return *this;
}
经检验,上面三种方法都没毛病,读者想用哪种就用哪种,看自己能理解那种了。