重新理解C11的右值引用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重新理解C11的右值引用相关的知识,希望对你有一定的参考价值。
参考技术A c中,左值其实就是 有名字的变量 ,而运算操作(加减乘除,函数返回值等)就是右值, 右值不允许被修改
c++中,相对于右值引入了一个新的概念, 基础类型右值不允许被修改,但用户自定义的类型,右值可以通过它的成员函数进行修改 。
这里要引入一个C11的新概念:C11要求所有的值只能为下面三种: 左值、将亡值、纯右值 。左值和右值都介绍过了,现在来解释一下什么是将亡值:将要被移动的对象、T&&函数的返回值、std::move返回值等
类的右值是一个临时对象 ,如果没有被绑定到引用,在表达式结束时就会被废弃。于是我们可以 在右值被废弃之前,移走它的资源进行废物利用,从而避免无意义的复制 。被移走资源的右值在废弃时已经成为空壳,析构的开销也会降低。
总结来说:1. 避免无意义复制 2.析构开销减少
GetA()被绑定在右值引用,所以生命周期被延长,减少了临时对象的拷贝和析构。
首先思考一下 指针悬挂出现的条件:
当类没有定义构造函数,我们实例化类的时候,会使用默认构造函数。如果我们类某个属性需要动态分配内存,那么这个属性很可能会被多次删除。
如果我们在上面没有使用深拷贝构造函数,而是使用了系统默认的构造函数,那么类内部的m_ptr将会被删除两次, 一次是临时右值析构的时候删除一次,第二次外面构造的a对象释放时删除一次 ,而这两个对象的m_ptr是同一个指针,这就是指针悬挂。
如何解决指针悬挂问题
可以看出下面的A(A&& a)的构造函数其实就是一个移动构造函数。
如果在使用左值的时候也希望能减少拷贝来优化性能,我们可以使用std::move来将左值转为右值。 move实际上它并不能移动任何东西,它唯一的功能是将一个左值强制转换为一个右值引用 。
move的源码如下
源码中的static_cast是什么
static_cast是一个 强制类型转换符 ,强制类型转换会告诉编译器:我们知道并且不会在意潜在的精度损失。
有时候我们需要按照参数的原本类型进行转发,而不需要进行默认的类型转换。那么我们就可以使用完美转发std::forward, std::forward按照参数的实际类型去匹配对应的重载函数,最终实现完美转发
对临时声明的右值引用
【中文标题】对临时声明的右值引用【英文标题】:rvalue reference to temporary declaration 【发布时间】:2016-01-30 13:02:29 【问题描述】:E && e0 = E () ;
E e1 ;
这两种对象声明的情况有什么不同吗? ;
【问题讨论】:
【参考方案1】:在你的例子中:
E()
的结果是一个右值(确切地说是一个右值);
e0
是一个左值,类型为E&&
(右值引用E
);
e1
也是一个左值,类型为E
;
e0
,通过绑定到E()
的结果,将其生命周期从临时延长到自动。
因此,如果以下代码在 E
和 E&&
之间没有区别(例如,decltype
会但 auto
不会),它们的行为将相同。
【讨论】:
以上是关于重新理解C11的右值引用的主要内容,如果未能解决你的问题,请参考以下文章