右值引用与转移语义

右值引用是C++11的新特性,而且最近也经常看到网上的代码里出现的move,因此非常想对于这方面做一个简单的了解。

我们在平常写代码的时候通常会遇到这样的场景,A变量在某个时刻要赋值给B变量,但与此同时之后A就不会再被使用了。我们在之前肯定是得把A拷贝一份给B。但是自从C11之后,我们就可以直接B=move(A)将A直接给B,同时A也就名负实亡了。相关的幕后操作又是什么呢?此时我们就需要介绍一下右值引用了。

首先说一下左值,通俗来说左值就是所有非临时的对象,可以在多条语句中被使用。而常量则只能在一句话中使用,比如int x=233; 233这个值就不可以被后面的语句引用了。

对于函数的参数,int &大家都很熟悉,这是一个引用,可以直接操作同一个对象。但是int &&我们之前却没有见过,这就是C11引入的黑魔法右值引用,请对这个保持敏感,因为这就是我们的重点。然后对于函数调用的参数匹配,右值和左值是必须匹配的,例如下面的代码实例。

如果我偏偏想对一个命名对象调用右值引用怎么办呢?你的回答可能很简单,强制转化不就OK了吗?例如process_value((int &&)a)或者这样process_value(static_cast<int&&>(a));,,然后在C11中我们就可以直接用右值引用来进行了,即process_value(std::move(a)).

到现在我们已经可以初见端倪了。编译器区分了左值和右值,对右值调用了转移构造函数和转移赋值操作符。节省了资源,提高了程序运行的效率。

有了右值引用和转移语义,我们在设计和实现类时,对于需要动态申请大量资源的类,应该设计转移构造函数和转移赋值函数,以提高应用程序的效率。

总结一下,如果已知一个命名对象不再被使用而想对它调用转移构造函数和转移赋值函数,也就是把一个左值引用当做右值引用来使用。

另外,在之前写C0文法编译器的时候,我发现我其实就遇到这样的锅,贴一段当时的代码。v_node的类型是map<string, vector>我本意是想删除其中的一个元素,但是由于auto &它只能绑定到一个可以修改的左值所以就必须得写成auto &&才可以,这个问题可以参考这个回答来仔细了解。

主要参考文章, https://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/index.html

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注