【C++右值引用】移动构造和移动赋值,万能引用,右值详讲

目录

1.右值和左值

2.左值引用和右值引用 

3.移动构造

4.移动构造和移动赋值的默认生成条件(重载赋值的右值引用和移动构造跟拷贝构造差不多) 

5.万能引用 (模板参数引用&&)


1.右值和左值

左值与右值是C语言中的概念,但C标准并没有给出严格的区分方式,一般认为:可以放在=左边的,或者能 够取地址的称为左值,只能放在=右边的,或者不能取地址的称为右值,但是也不一定完全正确

左值可以取地址,可以赋值的

  • 下面的a,r1,p,r2就属于左值
  • b,r3虽然是被const修饰不能赋值,但是也是左值,左值是能取地址的值,可以被const修饰也是左值
	int a = 10;
	int& r1 = a;
	int* p = &a;
	int& r2 = *p;

	const int b = 10;
	const int& r3 = b;

右值:不能取地址的值

  • 纯右值,比如:X+Y, 10。
  • 将亡值,比如:表达式的中间结果((X+(Y+Z))Y+Z的值)、函数按照值的方式进行返回(返回值)。 
	//常见的右值
    10;
	x + y;
	min(x, y);

2.左值引用和右值引用 

  • 左值引用:b,d
  • 右值引用:a1,b1,c1

左值引用使用:&,右值引用使用:&&同时它们也是可以交叉引用

    //左值引用左值
    int a=1;
    int& b=a;
    int* c=&a;
    int& d=*c;

    int X=10,int Y=20;
    //右值引用右值
    int&& a1=10;
    int&& b1=X+Y;
    int&& c1=min(X,Y);

 2.1左右值的交叉引用

  • 左值引用右值-- 不能直接引用,但是const 左值引用可以引用右值

  • 右值引用左值-- 不能直接引用,但是可以右值引用可以引用move以后左值

    //左值引用右值-- 不能直接引用,但是const 左值引用可以引用右值
    const int& a=2;

    //右值引用左值-- 不能直接引用,但是可以右值引用可以引用move以后左值
    int a1=1000000;
    int&& b1=move(a1)

2.2左值引用右值的具体情景

  1. 当参数直接传常数(右值),那么引用必须加一个const

3.移动构造

class string
	{
	public:
        // 拷贝构造
		string(const string& s)
			:_str(new char[strlen(s._str) + 1])
			, _size(s._size)
			, _capacity(s.s_capacity)
		{
			cout << "string(const string& s) -- 深拷贝" << endl;
			strcpy(_str, s._str);
		}

		// 移动构造
		string(string&& s)
			:_str(nullptr)
			, _size(s._size)
			, _capacity(s._capacity)
		{
			cout << "string(string&& s) -- 资源转移" << endl;
            _str = s._str;
            s._str = nullptr;
        }

		string operator+(char ch)
		{
			string tmp(*this);
			push_back(ch);

			return tmp;
		}

	private:
		char* _str;
		size_t _size;
		size_t _capacity; // 不包含最后做标识的\0
	};

3.1移动构造:资源转移,没有了深拷贝和delete效率大大提高

  1. 没有深拷贝了,析构也减少了,效率提升;
  2. 将亡值资源被转移了,它被换成nullptr,调析构函数,没有资源需要析构效率提高 

 3.5push_back的右值引用的重载

  • 所有容器调用push_back都有左值引用和右值引用版本

4.移动构造和移动赋值的默认生成条件(重载赋值的右值引用和移动构造跟拷贝构造差不多) 

  • 移动构造和移动赋值默认生成条件:当它本身被实现,且析构函数、拷贝构造、赋值运算符重载都没有实现才会默认生成;

5.万能引用 (模板参数引用&&)

  • 万能引用就是模板参数引用,使用的符号和右值引用相同:&&
  • 可以接受左值也可以接受右值
  • 接受后使用退化成了左值
void Fun(int& x) { cout << "左值" << endl; }
void Fun(int&& x) { cout << "右值" << endl; }
void Fun(const int& x) { cout << "const 左值" << endl; }
void Fun(const int&& x) { cout << "const 右值" << endl; }

template<class T>
void PerfectForward(T&& t)
{
	Fun(t);

	//Fun(std::forward<T>(t));
}
int main()
{
	PerfectForward(10);           // 右值

	int a;
	PerfectForward(a);            // 左值
	PerfectForward(std::move(a)); // 右值

	const int b = 8;
	PerfectForward(b);		      // const 左值
	PerfectForward(std::move(b)); // const 右值

	return 0;
}

5.1完美转发 

完美转发是目标函数总希望将参数按照传递给转发函数(forward)实际类型转给目标函数,而不产生额外的开销;如果相应实参是左值,它就应该被转发为左值;如果相 应实参是右值,它就应该被转发为右值

格式:forward<模板参数>(实参)

使用完美转发结果:

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值