前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >带右值引用的拷贝构造函数和运算符重载函数

带右值引用的拷贝构造函数和运算符重载函数

作者头像
lexingsen
发布2022-02-25 08:47:30
7380
发布2022-02-25 08:47:30
举报
文章被收录于专栏:乐行僧的博客

考虑一个占用堆资源类对象的拷贝构造和赋值运算符重载函数,当我们用一个临时对象去拷贝构造一个新对象或者赋值给一个已经存在的对象时,会出现一下的问题:如string类

代码语言:javascript
复制
#include <iostream>
#include <cstring>
using namespace std;

class MyString {
private:
	char *mptr;
public:
	MyString(const char *src = nullptr) {
		cout << "MyString(const char*)" << endl;
		if (src != nullptr) {
			mptr = new char[strlen(src) + 1];
			strcpy(mptr, src);
		} else {
			mptr = new char[1];
			*mptr = '\0';
		}
	}


	MyString(const MyString& src) {
		cout << "MyString(const MyString&)" << endl;
		mptr = new char[strlen(src.mptr) + 1];
		strcpy(mptr, src.mptr);
	}
		
	MyString& operator=(const MyString& src) {
		cout << "operator=(const MyString&)" << endl;
		if (this == &src) {
			return  *this;
		}
		delete[] mptr;
		mptr = new char[strlen(src.mptr) + 1];
		strcpy(mptr, src.mptr);
		return *this;
	}

	~MyString() {
		cout << "~MyString()" << endl;
		delete[] mptr;
		mptr = nullptr;
	}

	const char* c_str() const {
		return mptr;
	}
};

MyString getString(MyString &s) {
	const char* t = s.c_str();
	MyString res(t);
	return res;
}

int main() {
	MyString s1("aaaaaaaaaaaaaaaaaaaaaaaaaaa");
	MyString s2;
	s2 = getString(s1);
	return 0;
}

1.当我们用临时对象去拷贝构造一个新对象时。 MyString res = MyString(“aaaa”);

在这里插入图片描述
在这里插入图片描述

显然,这样做很不合理,很浪费!!!你临时对象用完就析构了,还不如直接给我新对象用,避免开辟新空间,避免拷贝!!!

在这里插入图片描述
在这里插入图片描述

到这里就引出了第一个主题,带右值引用的拷贝构造函数。因为临时对象是右值。临时对象用完就要析构的,那就把临时对象占用的资源直接给新对象就好了。这样做一方面避免了在原来拷贝构造函数需要首先申请空间,然后进行拷贝的麻烦。另一方面避免临时对象析构时还有释放堆资源的麻烦,一举两得!!!

代码语言:javascript
复制
MyString(MyString &&src) {
	mptr = src.mptr;
	src.mptr = nullptr;
}

2.当我们用临时对象去赋值一个已经存在的对象时。这里指的对象都是持有堆资源的对象。 首先,被赋值的对象要释放自己占用的堆资源,然后申请一个和临时对象指向堆资源一摸一样大小的空间,之后将临时对象指向堆空间的内容拷贝到自己的堆空间中。 这里同样存在着上边的问题,我临时对象给你赋值完我就析构了,堆资源也在析构函数中被释放了,但是你被赋值的对象还得申请空间,还得拷贝,你直接用临时对象的那块堆资源不就好了。

在这里插入图片描述
在这里插入图片描述

问题就处在临时对象赋值完就析构了,与其白白浪费,不如拿来直接使用,有点“偷”的感觉!!!

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
MyString& opeator=(MyString &&s) {
	if (this == &s) {
		return *this;
	}
	delete[] mptr;
	mptr = s.mptr;
	s.mptr = nullptr;
	return *this;
}

结论: 至此,通过一个例子我们总结出了带右值引用的拷贝构造函数和运算符重载函数所带来效率的提升,以及为什么可以这样处理的原因。在实际开发中,当出现一定要用临时对象作为返回值,要用临时来进行赋值时,我们可以为其类实现带右值引用的拷贝构造函数和运算符重载函数,在程序的效率上会得到很大的提升。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档