ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

右值引用

2021-03-14 16:03:47  阅读:201  来源: 互联网

标签:std pstr const String 右值 rhs 引用 cout


右值引用的由来

看个例子:

#include <vector>
#include <iostream>
#include <string.h>

class String {
public:
	String();
	String(const char* str);
	String(const String& rhs);

	String& operator=(const String& rhs);
	~String();

	friend std::ostream& operator<<(std::ostream& os, const String& rhs);
private:
	char* _pstr;
};

String::String()
	:_pstr(new char[1]())
{
	std::cout << "String::String()" << std::endl;
}

String::String(const char* str)
{
	std::cout << "String::String(const char* str)" << std::endl;
	_pstr = new char[strlen(str) + 1]();
	strcpy(_pstr, str);
}

String::String(const String& rhs)
{
	std::cout << "String::String(const String& rhs)" << std::endl;
	_pstr = new char[strlen(rhs._pstr) + 1]();
	strcpy(_pstr, rhs._pstr);
}

String& String::operator=(const String& rhs)
{
	if (this == &rhs) {
		delete[]_pstr;
		_pstr = new char[strlen(rhs._pstr) + 1];
		strcpy(_pstr, rhs._pstr);
	}
	return *this;
}

String::~String()
{
	std::cout << "String::~String()" << std::endl;
	if (_pstr != NULL) {
		delete[]_pstr;
	}
}

std::ostream& operator<<(std::ostream& os, const String& rhs)
{
	os << rhs._pstr;
	return os;
}

int main()
{
	std::vector<String> vecInt;
	vecInt.push_back("hello,world");
	std::cout << vecInt[0] << std::endl;
}

执行结果如图
在这里插入图片描述
std::vector vecInt;
vecInt.push_back(“hello,world”);
可以看到这两句代码实际发生了这三个步骤:
①调用String::String(const char *); 通过hello,world构造一个临时对象
②String::String(const String&); 第一步是临时对象,放到容器中需要左值,因此要通过第一步构造的string对象调用复制构造函数构造出一个持久化的对象放到容器中
③String::~String()

这里产生了两次构造和析构。问题就在于临时对象的构造和析构带来了不必要的资源拷贝,有什么办法可以在第②步识别出临时对象,将临时对象的资源转移到新的对象中,消除不必要的拷贝,因此引入了右值引用。

const引用小知识点

const int& m = a; // 常量引用可以绑定到左值
const int& n = 123; // 常量引用也可以绑定到右值
int& p = a;  
int& k = 123;// 编译报错,非常量引用的初始值必须为左值

因此上面的例子中String::String(const String&rhs) ,复制构造函数内部无法识别出rhs是左值还是右值,C++11引入右值引用,例:int& k = 123 改写成为 int&& k = 123
ps:常量右值引用没有实际意义,右值引用的初衷在于移动语义,而移动就意味着修改

具有移动语义的string

基于上面例子新增两个函数 移动复制构造函数和移动赋值运算符函数

#include <vector>
#include <iostream>
#include <string.h>

class String {
public:
	String();
	String(const char* str);
	String(const String& rhs);
	// 移动构造函数
	String(String&& rhs);

	String& operator=(const String& rhs);
	// 移动赋值运算符函数
	String& operator=(String&& rhs);
	~String();

	friend std::ostream& operator<<(std::ostream& os, const String& rhs);
private:
	char* _pstr;
};

String::String()
	:_pstr(new char[1]())
{
	std::cout << "String::String()" << std::endl;
}

String::String(const char* str)
{
	std::cout << "String::String(const char* str)" << std::endl;
	_pstr = new char[strlen(str) + 1]();
	strcpy(_pstr, str);
}

String::String(const String& rhs)
{
	std::cout << "String::String(const String& rhs)" << std::endl;
	_pstr = new char[strlen(rhs._pstr) + 1]();
	strcpy(_pstr, rhs._pstr);
}

String& String::operator=(const String& rhs)
{
	if (this == &rhs) {
		delete[]_pstr;
		_pstr = new char[strlen(rhs._pstr) + 1];
		strcpy(_pstr, rhs._pstr);
	}
	return *this;
}

String::~String()
{
	std::cout << "String::~String()" << std::endl;
	if (_pstr != NULL) {
		delete[]_pstr;
	}
}

String::String(String&& rhs)
{
	std::cout << "String::String(String&& rhs)" << std::endl;
	_pstr = rhs._pstr;
	rhs._pstr = NULL; // 注意这里不要忘了
}

String& String::operator=(String&& rhs)
{
	std::cout << "String& String::operator=(String&& rhs)" << std::endl;
	if (this == &rhs) {
		delete []_pstr;
		_pstr = rhs._pstr;
		rhs._pstr = NULL; // 注意这里不要忘了
	}
	return *this;
}

std::ostream& operator<<(std::ostream& os, const String& rhs)
{
	os << rhs._pstr;
	return os;
}

int main()
{
	std::vector<String> vecInt;
	vecInt.push_back("hello,world");
	std::cout << vecInt[0] << std::endl;
}

执行结果如下,可以看到helloworld产生的临时对象申请的空间直接转移给了新对象:
在这里插入图片描述
注意:一定不要忘了给临时对象赋空,不然临时对象销毁时就把该空间释放了。

参考资料:
https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
http://thbecker.net/articles/rvalue_references/section_01.html
https://www.jianshu.com/p/d19fc8447eaa
https://zhuanlan.zhihu.com/p/107445960
https://zhuanlan.zhihu.com/p/99524127
《深入理解C++11》

标签:std,pstr,const,String,右值,rhs,引用,cout
来源: https://blog.csdn.net/qq_43003442/article/details/114580438

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有