深浅拷贝的区别很大,使用不对会引起BUG。
先看一下深浅拷贝的原理图。
浅拷贝:
浅拷贝可以获得相同的值,但是同样的,会使用同一块空间。这时候对s2进行操作,s1的值也会相应改变,这是浅拷贝最大的坏处。
拷贝构造
这里我们用自定义类验证一下(这里使用的是默认拷贝构造)
#include<iostream>
#include<string>
using namespace std;
namespace lys1 {
class string {
char* _str;
public:
string(const char* str = "") {
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
};
}
int main() {
lys1::string s1("hello word!");
lys1::string s2(s1);
}
得出的结果在监视窗口中观察是这样的
s1和s2的_str是相同地址,且值相同。
而深拷贝最大的不同的就是,深拷贝会额外开辟一块新的空间来存储拷贝来的值
string(const string& str) {
_str = new char[strlen(str._str) + 1];
strcpy(_str, str._str);
}
使用深拷贝的拷贝构造函数以后,得到的结果是:
s1和s2的_str地址发生了改变,地址已经不同,这说明这一次的拷贝构造已经是深拷贝
由此可得,默认的拷贝构造是浅拷贝,深拷贝需要自行定义。
上面的方法是传统写法,这里看一下现代写法。
string(const string& s) {
_str = nullptr;
string tmp(s._str);
swap(_str, tmp._str);
}
现代写法突显了复用的好处,在赋值操作符上使用现在写法时将大大提升便利性。
赋值操作符重载
string& operator=(const string& str) {
if (this != &str) {
delete[] _str;
_str = new char[strlen(str._str) + 1];
strcpy(_str, str._str);
}
return *this;
}
传统写法都是开空间然后拷贝,下面看现代写法。
string& operator=(const string& s) {
if (this != &s) {
string tmp(s);
swap(_str, tmp._str);
}
return *this;
}