C++11右值引用和move语义

来源:互联网 发布:手机健身运动软件 编辑:程序博客网 时间:2024/06/07 17:07

最近面试被问到这个没答上来,在此整理一下

右值引用


在C++11当中又一个概念叫做右值引用,这个概念我们首先要能够进行区分左值和右值的概念,左值就是一个具体的内存对象,可以修改的,右值就是一个值,这个值可以赋值给其他的。

右值引用的作用是让我们能够得到临时对象的所有权,这样我们就可以去修改临时对象了。

int i = 50;int &a = i;    //左值引用int &&ra = 42;    //右值引用int &&rb = 42*i;    //右值引用const int b = 5;const int &&rc = a+b;    //右值引用

一般来说,左值表达式表示的是对象的身份,右值表达式表示的是对象的值属性。

右值引用无法绑定到左值上进行操作。

左值有持久的状态,而右值要么是字面常量,要么是在表达式求职过程当中创建的临时对象。

所以一般来说右值引用只能绑定到临时对象,并且这个对象要被销毁,这个对象没有其他用户。

这也就意味着使用右值引用的代码可以自由的接管所引用的对象的资源。

在右值引用当中,右值引用我们是看做左值的,所以我们不能把右值引用赋值给一个右值引用。

int &&a=42;int &&rr=a; //错误,不能把右值引用赋值给右值引用

因为变量就是一个左值,当然右值引用也是一个左值,所以不能上面这样操作。

右值引用可以简化代码,并且提高程序的效率。

转移语义


右值引用有一个概念叫做转移语义:

转移语义是右值引用支持的,就是可以把临时对象的创建直接转移过去,让你继续使用。我们使用了转移语义,临时对象的资源就可以很好的转移到其他对象里面。

我们要实现转移语义的话,那么我们就需要定义转移构造函数,另外也可以去定义转移赋值操作。

我们的操作依然就是首先创建临时对象,然后操作临时对象,临时对象的内容进行了转移。

例如我们定义一个class A的转移构造函数:

class A{public:        A(A &&tmp)        {            cout<<"move constructor"<<endl;            _ptr = tmp._ptr;            _a = tmp._a;            tmp._ptr = NULL;            TMP._a = 0;        }private:    int _ptr;    int _a;};

需要注意的几点是我们定义的时候:
- 参数的符号必须是右值引用
- 参数不可以是常量。
- 另外记得对右值进行资源修改,否则会析构临时对象。

move操作


move操作提供给我们一种方式,能够显式地把一个左值转换为对应地右值引用类型。
我们可以通过move得到绑定到左值上的右值引用。

move操作牵扯的一个东西叫做拷贝临时对象。

例如:

int i = 50;int &&rc = std::move(i);    //这个就是采用了move操作,move可以获取到变量i的右值引用。

在我们使用了move以后,也就意味着除了对rc进行赋值或销毁她以外,我们将不再去使用它。

例:

string s1("hello");string s = s1 + “a” +"b"+"c";

上述问题进行操作的时候,这个时候会产生大量的临时的拷贝对象,这样会影响性能。

move语义可以在你使用临时对象的时候避免拷贝,可以安全的使用在临时对象里面的资源。

有了move,我们就可以对已知的命名对象写出它的转移构造函数和转移赋值函数。