【C++】左值、右值、语义移动和完美转发

右值引入的目的是为了对象移动:
因为在很多情况下,对象拷贝会经常发生,但是很多对象在拷贝后就直接被销毁了。这对性能是一个很大损耗。在重新分配内存的时候,从旧的内存将元素拷贝到新的内存中是不必要的。更好的方法是移动元素。

C++11 扩展了右值的概念,分为了纯右值和将亡值。
纯右值:
非引用返回的临时变量;运算表达式的结果;字面常量(“abs”不是,字符串常量是有地址的)
将亡值:与右值引用相关的表达式
左值:是具名的,且有地址

在旧的C++ 标准中是没有直接移动元素的方法,只有拷贝构造函数。为了实现元素移动,引入了【右值引用】的概念。

右值引用的一个重要性质:只能绑定到一个即将销毁的对象。 因此可以自由的将一个右值引用的资源移动到另一个对象中。

而左值是持久的,分配一个内存中的。右值是暂时的,例如一个运算表达式

左值引用可以绑定右值,但是右值引用不能绑定左值。为了实现对左值的右值引用,可以使用std:: move()将一个左值转换成右值。这样就可以实现对左值的右值引用了。注意:调用move后,就不能对移动后的对象值做出任何假设。可以销毁或者重新赋值。

区分一个左值和右值的便捷方法,就是看能不能对其表达式取地址,如果能,就是左值,不能就是右值。

有了右值引用的概念,就可以设计【移动构造函数】和【移动赋值运算符】

类似于拷贝构造函数的设计,第一个参数是对应类别的一个引用,但是这里是右值引用。同时移动构造函数还必须保证,在资源移动之后,对应的源对象的销毁是无害的。移动构造函数是不分配任何新的内存的。

【复制构造器】接受一个左值,之后还能继续用。【移动构造器】直接偷窃资源,偷窃后的源对象就不能用了。

只有一个类没定义任何自己版本的拷贝控制成员,并且类的每一个非static 成员都是可以移动的,编译器才会为它合成移动构造函数或移动赋值运算符。

移动右值,拷贝左值;如果没有移动构造函数,右值也会被拷贝;

左值和右值的参数类型推导

【左值引用函数参数推导】
当一个函数参数的模板类型参数是一个左值引用,只能传递一个左值。

template <typename T> void f1(T&)
f1(5);// error

但是如果一个函数参数是 const T&,那边就可以传递任何类型的实参,可以绑定一个右值。

【右值引用函数参数推导】
C++有两个例外的绑定规则:

  1. 当将一个左值传递给函数的右值引用参数时,且此右值引用指向的是模板类型参数,编译器就可以推导为实参的左值引用类型。
  2. 如果创造了一个引用的引用,那么这些引用就会形成“折叠”,引用会折叠成一个普通的左值引用类型。

将引用折叠规则和右值引用的特殊规则组合在一起,就可以对一个左值调用带模板类型推导的右值引用。
万能引用:万能引用就是发生了类型推导,如果已经确定了类型,如int && 就是右值引用。如果发生了类型推导,那就是万能引用。
C++ 11 中使用了引用折叠 的推导规则。
在这里插入图片描述

template<class T>
void bar(T && t){} // 这里的t就是万能引用
auto && z = get_val(); //z 也是万能引用;

万能引用为的就是完美转发。完美转发就是保持实参的实际类型,如果实参是左值,那么在调用函数中继续保持着其左值属性。右值同理。

template <typename T> void f3(T&& val){
	T t = val; 
}

如果右值调用 f3 如 字面常量 42, T 就是 int。如果是调用左值 i 那么 T 就是 int&。

理解 std:move

template <typename T>
typename reomve_reference<T>::type&& move(T&& t){
 return static_cast<typename remove_reference<T>::type &&>(t);
}

其中 reomve_reference 的作用是返回一个数据结构,其中关键字 type 中包含了变量的类型信息。

从一个左值static_cast 到一个右值引用是允许的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值