【C++拓展】深拷贝的传统写法vs现代写法,你更喜欢哪个?

        这篇呢是关于深拷贝的拓展知识。目前我们学到的知识中,会用到深拷贝就是拷贝构造赋值运算符重载。传统写法的代码实现相信大家已经是手拿把掐,知道现代写法如何实现吗?我们来一起看看。(全文以我们前面模拟实现的string类为背景,文中函数的返回值类型最好是string的引用)

1.拷贝构造和operator=的传统写法

已经存在的对象初始化另一个刚创建的对象,此时调用拷贝构造

string s1("hello world");
string s2 = s1;//此时调用拷贝构造
//s2(s1)和s2 = s1一个意思,写法不同而已
string(const string& s)//拷贝构造传统写法
{
	_str = new char[s._capacity + 1]; //s2开和s1一样的大小
	strcpy(_str, s._str);//拷贝数据
	_size = s._size;
	_capacity = s._capacity;
}

两个已经存在的对象之间的拷贝复制,就调用operator=赋值运算符重载。

string s1("hello world");
string s2("xxxxxxxx");
s2 = s1;//s1,s2都已经存在,此时是赋值
string operator=(const string& s) //传统赋值重载
{
	if (this != &s) //不是自己给自己赋值时
	{
		delete[] _str; //释放原来空间
		_str = new char[s._capacity + 1];
		_size = s._size;
		_capacity = s._capacity;
	}
	return *this;
}

传统写法呢就是我们自己开空间,自己拷贝数据,现代写法就是我们让“别人”帮我们开空间,帮我们拷贝数据。

 2.拷贝构造现代写法

先看代码再解释。这里s就是s1,隐形的this指针就是s2。

//拷贝构造s2(s1)
string(const string& s)//拷贝构造现代写法
{
	string temp(s._str);
	swap(_str, temp._str);
	swap(_size, temp._size);
	swap(_capacity, temp._capacity);
}

s2想和s1有一样大的空间,一样的值,我们不自己处理这些事,让temp来处理,temp处理好了,s2和temp一交换。

这样处理的前提是,我们在成员函数声明的地方给了缺省值,不然会对随机值释放,如下。

private:
	char* _str = nullptr;
	size_t _size = 0;
	size_t _capacity = 0;

是不可以对随机值释放的,相当于释放的野指针,这里要注意一下。

这里的交换呢,我们还可以单独写一个交换函数。

void swap(string& s)
{
	//调用算法库里面的swap函数
	std::swap(_str, s._str);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

然后再调用这个自己写的swap函数。

//s2(s1)
string(const string& s)//拷贝构造现代写法
{
	string temp(s._str);
	swap(temp);
}

 看到这里我相信你一定有很多疑惑,不着急,存在即合理,我慢慢解释,来画图分析。

开始的时候s2是指向nullptr,因为我们前面给的缺省值是nullptr。

然后我们构造了一个temp对象,temp里面存和s1一样的内容

此时temp里面的内容就是s2想要的,this就是s2,然后s2和temp交换

temp出了作用域就销毁了,此时temp是nullptr,这里会调用析构函数,可以释放空,所以前面我们才强调要给缺省值。

此时s2就和s1一样大,而且内容也一样。但是这个活是“别人”干的,是temp干的,然后s2通过交换,掠夺“别人”的“成果”。

3.operator=的现代写法

赋值也可以用和拷贝构造类似的写法。

//赋值s2 = s1;
string operator=(const string& s)//赋值重载现代写法
{
	if (this != &s) //不是自己给自己赋值时
	{
		string temp(s._str);
		swap(temp);
	}
	return *this;
}

s2想和s1有一样大的空间,一样的值,还是一样,我们不自己处理这些事,让temp来处理。

 我们构造了一个temp对象,temp里面存和s1一样的内容

此时temp里面的内容就是s2想要的,this就是s2,然后s2和temp交换

 temp出了作用域就销毁了,此时temp是"xxxxxxxx",这里会调用析构函数

最后返回*this,就是"hello world"。此时s2就和s1一样大,而且内容也一样。

从图的分析可以看出,我们不仅掠夺了temp的成果,还让temp把s2原来的空间给释放了,在传统写法中我们首先要释放s2的旧空间,现在我们都不用自己释放了。

传统写法就是我们自己完成所有步骤,现代写法就是让“别人”帮我们完成。

4.operator=现代写法的再变形

//赋值重载s2 = s1;
string operator=(string s)
{
	swap(s);
	return *this;
}

参数列表不再引用传参,因为这个代码下引用传参会改变s1。

this直接和s交换。 

 然后返回*this,出作用域s销毁。

传统写法和现代写法你更喜欢哪个呢?我们以后也会用到现代写法的,就介绍到这里了,拜拜~

猜你喜欢

转载自blog.csdn.net/2402_82757055/article/details/143259655