重新理解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 也是一个左值,类型为Ee0,通过绑定到E() 的结果,将其生命周期从临时延长到自动。

因此,如果以下代码在 EE&& 之间没有区别(例如,decltype 会但 auto 不会),它们的行为将相同。

【讨论】:

以上是关于重新理解C11的右值引用的主要内容,如果未能解决你的问题,请参考以下文章

[转][c++11]我理解的右值引用移动语义和完美转发

如何评价 C++11 的右值引用(Rvalue reference)特性?

深入思考右值引用

c++11的右值引用移动语义

转载C++ 11中的右值引用

对临时声明的右值引用