前言
先抛出两者的概念:
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共 享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。要解决浅拷贝问题,C++中引入了深拷贝。
深拷贝:如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。
简单的来说,浅拷贝是增加了一个指针,指向原来已经存在的内存。而深拷贝是增加了一个指针,并新开辟了一块空间,让指针指向这块新开辟的空间。
浅拷贝
看一段代码:
class String
{
public:
String(const char* str = "")
{
if (nullptr == str)
{
_str = new char[1];
*_str = '0';
}
else
{
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
}
//编译器生成的默认拷贝构造函数---浅拷贝
String(const String& s)
: _str(s._str)
{
}
//编译器生成的默认赋值运算符重载---浅拷贝
String& operator=(const String& s)
{
_str = s._str;
return *this;
}
~String()
{
if (_str)
{
delete[] _str;
_str = nullptr;
}
}
friend ostream&operator<<(ostream & _cout, const String &s)
{
_cout << s._str;
return _cout;
}
private:
char* _str;
};
int main()
{
String s1("hello");
String s2(s1);
String s3("world");
s3 = s1;
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
return 0;
}
结果:
查看监视窗口,我们发现s1、s2、s3在同一块空间:
我们写的析构函数:
~String()
{
if (_str)
{
delete[] _str;
_str = nullptr;
}
}
s3先析构,析构完后空间释放掉,因为s1、s2、s3在同一块空间,所以这个时候已经没s1、s2啥事了~~~,所以出现了崩溃。
深拷贝
在上边的代码的基础上,修改了拷贝构造函数和赋值运算符函数
class String
{
public:
String(const char* str = "")
{
if (nullptr == str)
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=(const 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;
}
}
friend ostream&operator<<(ostream & _cout, const String &s)
{
_cout << s._str;
return _cout;
}
private:
char* _str;
};
int main()
{
String s1("hello");
String s2(s1);
String s3("world");
s3 = s1;
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
return 0;
}
结果:
此时,s1、s2、s3在不同空间
总结
浅拷贝:只是增加一个指针,指向原来的空间。多个对象在底层共用一份资源,最终在这些对象销毁时,该份资源释放多次,而引起代码崩溃。
深拷贝:新增加指针,并新开辟空间,让每个对象中都拥有自己独立的资源。