1.浅拷贝

在学习string的时候,我们会遇到需要对string类进行拷贝的情况。通常,我们进行数据拷贝只需要将一个类里的基本数据进行值拷贝即可。但是实际上,直接进行值拷贝对于string类来说是不合理的。

class string
{
	//...
	string& operator=(const string& s)//看似正确的拷贝方式
	{
		_str = s._str;
		_size = s._size;
		_capacity = s._capacity;
		return *this;
	}
private:
	char* _str;
	size_t _size;
	size_t _capacity;
};

在创建一个string类时,我们会使用new在堆上申请空间,用于存放我们的字符串。并且使用成员变量保存这块空间的地址。

而在拷贝时,如果我们仅仅进行值拷贝,那么会导致两个对象同时指向同一块空间。而对两者中的任意一方进行修改,势必会因为所指向的空间相同,而影响到另一方。

String 拷贝 java_String 拷贝 java

并且在析构释放资源的时候,因为两者指向了同一块空间,必然会导致对同一块空间的两次释放,直接导致报错。

所以,对于单纯的值拷贝(也就是浅拷贝),在string类的拷贝上并不可取,取而代之的是深拷贝。

2.深拷贝

要解决上面的问题,只需要让两个类拥有自己独立的空间就可以了,这样,无论是在修改还是在释放资源时,都不会影响到对方。

所以,深拷贝就是开辟一个新空间,将S1的内容拷贝过去。

下面是深拷贝的写法:

string& operator=(string s)//利用s的资源进行深拷贝
{
std::swap(_str,s._str);
std::swap(_size,s._size);
std::swap(_capacity,s._capacity);
return *this;
}

这里我们利用了局部对象会在结束作用域后进行释放的特点,完成深拷贝。

对象s是形参,实际上是对被拷贝对象的深拷贝产物,其拥有独立的空间,并且会在离开函数后被释放。我们知道,对形参的修改并不会影响实参,所以从这点下手就可以简单的完成深拷贝。

我们只需要将s所指向的空间与拷贝方的空间交换,这样拷贝方就得到了自己需要的资源,而s则得到了拷贝方所遗弃的资源。而这部分资源则会在函数结束,s释放资源时被释放。

这样,拷贝方就拥有了独立的空间,巧妙的完成了深拷贝。