左值引用与右值引用

左值与右值

概念
左值与右值是C语言中的概念,但是C标准并没有给出严格的区分方式,一般认为:可以放在 = 左边的(一般是可以修改的值) 或者 能取地址的称为左值只能放在 = 右边(一般是不可修改的一些值),或者不能取地址的值称为右值。(如:常量、临时变量、表达式的返回值)

具体解释:

  1. 普通类型的变量,因为有名字,可以取地址,都认为是左值。
  2. const修饰的常量,不可修改,只读类型的,理论上应该按照右值对待,但因为其是可以取地址的,C++1认为其是左值。
  3. 如果表达式的运行结果是一个临时变量或对象,认为是右值。
  4. 如果表达式运行结果或单个变量是一个引用则认为是左值。

C++11对右值进行了严格的区分:

  • C语言中的纯右值,比如:a+b,100;
  • 将忘值。比如:表达式的中间结果,函数按照值返回的方式进行返回。

左值引用与右值引用

  • 他俩都是给对象取别名;
  • 左值引用一般是给左值取别名,右值引用一般给右值取别名;

左值引用(&) 右值引用(&&)

在这里插入图片描述
那么有没有将左值处理为右值的情况呢??当然是有的!!

move告诉编译器我们有一个左值,但我们希望像一个右值一样处理它。注意:调用move意味着承诺:我们要放弃对move对象的资源管理。
在这里插入图片描述

为什么要提出右值引用呢??它的价值何在??

值的形式返回对象的缺陷

如果一个类中涉及到资源管理,用户必须显式提供拷贝构造、赋值运算符重载以及析构函数,否则编译器将会自动生成一个默认的,如果遇到拷贝对象或者对象之间相互赋值,就会出错,比如:

class String
{
public:
	String(char* str = "")
	{
		//cout << "String()" << endl;
		if (str == nullptr)
		{
			str = "";
		}
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	// 拷贝构造----深拷贝
	String(const String& s)
		:_str(new char[strlen(s.c_str())+1])
	{
		cout << "String(String&)" << endl;
		strcpy(_str, s._str);
	}
	// 移动构造-----移动拷贝
	/*String(String&& s)
		:_str(nullptr)
	{
		cout << "String (String&& s)" << endl;
		std::swap(_str, s._str);
	}*/

	//拷贝赋值----深拷贝
	String& operator=(const String& s)
	{
		cout << "String& operator=(const String& s)" << endl;
		if (this != &s)
		{
			char* tmp = new char[strlen(s.c_str()) + 1];
			strcpy(tmp, s.c_str());
			delete[] _str;
			_str = tmp;
		}
		return *this;
	}
	// 移动赋值----移动拷贝
	/*String& operator=(String&& s)
	{
		cout << "String& operator=(String&& s)" << endl;
		std::swap(_str, s._str);
		return *this;
	}*/

	String& operator+=(const String& s)
	{
		char* pTemp = new char[strlen(_str) + strlen(s._str) + 1];
		strcpy(pTemp, _str);
		strcpy(pTemp + strlen(_str), s._str);

		std::swap(_str, pTemp);
		return *this;

	}
	String operator+(const String& s)
	{
		char* pTemp = new char[strlen(_str) + strlen(s._str) + 1];
		strcpy(pTemp, _str);
		strcpy(pTemp + strlen(_str), s._str);
		String strRet(pTemp);
		
		return strRet;

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

	~String()
	{
		if (_str)
			delete[] _str;
	}
private:
	char* _str;
};

int main()
{
	String s1("hello");
	String s2("world");
	String s3 = s1 + s2;  // s1+s2,是传值返回,当没有
	String s4 = s1 += s2;
	//cout << endl;

	String s5;
		s5 = s1 + s2;
	
	cout << endl;
	
	String s6;
		s6= s1 += s4;
		
	system("pause");
	return 0;
}

在这里插入图片描述
当然经过编译器优化之后,看起来效率并没有降低,但是接下来这种情况呢??

在这里插入图片描述
那么能否对这种情况进行优化呢????

移动语义

C++11提出了移动语义概念,即:将一个对象中资源移动到另一个对象中的方式,可以有效缓解该问题。
要实现移动语义就必须使用右值引用。
在这里插入图片描述
那上面的例子来说:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

注意:

  1. 移动构造的函数参数千万不能设置程const类型的右值引用,因为资源无法转移而导致移动语义失效。
  2. 再C++11中,编译器会为类默认生成一个移动构造,该移动构造为浅拷贝,因此当类中涉及到资源管理时,用户必须显示定义自己的移动构造。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值