在C++中,字符串是用String类型定义的,字符串拷贝分为浅拷贝(位拷贝)和深拷贝两种,下面给出了深拷贝的两种不同的实现方式(普通版和简洁版)
浅拷贝
首先什么是浅拷贝?
浅拷贝又称为位拷贝,编译器只是将对象中的值拷贝过来,如果对象中管理了资源,就会导致多个对象共享同一份资源,当释放时就会进行多次释放造成程序错误。
class String
{
public:
String(const char* pStr = "")
{
//若指针为空,就让指针指向一个空字符串
if (NULL == pStr)
{
pStr = "";
}
//开辟空间,将参数的内容拷贝到类的_pStr中
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
~String()
{
if (_pStr)
delete[] _pStr;
}
private:
char* _pStr;
};
int main()
{
String s1("hello");
//拷贝构造函数和赋值函数只进行值拷贝,
//两个对象共用同一块空间,对象销毁时就会发生内存访问违规
String s2(s1);
String s3;
s3 = s1;
return 0;
}
如下图:两个对象共用同一块空间(0x007e4e98),对象销毁时就会释放两次从而发生内存访问违规
深拷贝
看完了浅拷贝,也知道它如果管理了资源进行浅拷贝就会发生错误,那什么是深拷贝呢?
深拷贝指的是每个对象拥有自己独立的资源,必须程序员显式的提供拷贝构造函数和赋值运算符重载,这样对象销毁时就不会发生内存违规操作
深拷贝有两种实现方式:
1)普通版:为每一个对象开辟一个新的空间
class String
{
public:
String(const char* pStr = "")
{
//若指针为空,就让指针指向一个空字符串
if (NULL == pStr)
{
pStr = "";
}
//开辟空间,将参数的内容拷贝到类的_pStr中
_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* pStr = new char[strlen(s._pStr) + 1];
strcpy(pStr, s._pStr);
delete _pStr;
_pStr = pStr;
}
return *this;
}
~String()
{
if (_pStr)
delete[] _pStr;
}
private:
char* _pStr;
};
2)简洁版:(调用构造函数创建临时对象,用临时对象和当前对象交换成员变量)
class String
{
public:
String(const char* pStr = "")
{
//若指针为空,就让指针指向一个空字符串
if (NULL == pStr)
{
pStr = "";
}
//开辟空间,将参数的内容拷贝到类的_pStr中
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr,pStr);
}
//简洁版拷贝构造函数
String(const String&s)
:_pStr(NULL)
{
String strTemp(s._pStr);
swap(_pStr, strTemp._pStr);
}
//简洁版,赋值操作符重载
String& operator=(String& s)
{
if (this != &s)
{
String strTemp(s._pStr);
swap(_pStr, strTemp._pStr);
}
return *this;
}
~String()
{
if (_pStr)
delete[] _pStr;
}
private:
char* _pStr;
};