谈一下深浅拷贝以及其写法
浅拷贝
首先看一下浅拷贝到底是个啥,浅拷贝是不用写拷贝构造函数的。
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
如果属性是基本类型,拷贝的就是基本类型的值;
如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间,浅拷贝只是一种简单的拷贝,让几个对象公用一个内存,然而当内存销毁的时候,指向这个内存空间的所有指针需要重新定义,不然会造成野指针错误。
举个具体的例子来说比如成员有指针,如果做了拷贝的话,析构的时候就会析构两次,造成经典的错误。
总结一下,基本类型浅拷贝没问题,引用类型浅拷贝就会出问题,所以这里就必须引出深拷贝来解决这个问题。
深拷贝
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。拷贝对象时,新开一块跟你一样大的空间,再把原对象空间上的值拷贝过来。说人话其实这里就是涉及到解决指针开空间这种资源管理的问题。
下面这段代码给出了深拷贝的拷贝构造函数、赋值运算符重载以及析构函数。
namespace yzy
{
class string
{
public:
string(const char* str):_str(new char[strlen(str)+1])//构造函数这样写
{
strcpy(_str,str);
}
//s2(s1) 深拷贝
//深拷贝传统写法
string(const string& s)
:_str(new char[strlen(s._str)+1])
{
strcpy(_str,s._str);
}
//赋值运算符重载
//s1 = s3
string& operator=(const string& s)
{
if(this!=&s)
{
_str = new char[strlen(s._str)+1];
delete[] _str;
strcpy(_str,s._str);
}
return *this;
}
//析构函数
~string()
{
delete[] _str;
_str = nullptr;
}
private:
char* _str;
};
void test_string1()
{
string s1("hello");
s1[0]='x';
string s2(s1);
}
}
其实拷贝构造函数和赋值运算符重载还有现代写法。
构造函数:
//s2(s1)
string(const string& s)
:_str(nullptr)
{
string tmp(s.str);//拿s的成员进行构造
swap(_str,tmp._str);
}
赋值运算符:
//s1=s2
string& operator=(const string& s)
{
if(this!=&s)
{
string tmp(s.str);
swap(_str,tmp._str)
}
return *this;
}