右值引用

右值引用

右值引用是C++11引入的与Lambda表达式齐名的重要特性之一。它的引入解决了C++中大量的历史遗留问题,消除了诸如std::vectorstd::string之类的额外开销,也才使得函数对象容器std::function成为了可能。

左值、右值的纯右值、将亡值、右值

左值(lvalue, left value),顾名思义就是赋值符号左边的值。准确来说,左值是表达式(不一定是赋值表达式)后依然存在的持久对象。右值(rvalue, right value),右边的值,是指表达式结束后就不再存在的临时对象。

C++11中为了引入强大的右值引用,将右值的概念进行了进一步的划分,分为:纯右值、将亡值。纯右值(prvalue, pure rvalue),纯粹的右值,要么是纯粹的字面量,例如10, true;要么是求值结果相当于字面量或匿名临时对象,例如1+2。非引用返回的临时变量、运算表达式产生的临时变量、原始字面量、Lambda表达式都属于纯右值。将亡值(xvalue, expiring value),是C++11为了引入右值引用而提出的概念(因此在传统C++中,纯右值和右值是统一个概念,也就是即将被销毁、却能够被移动的值。

将亡值可能稍有些难以理解,我们来看这样的代码:

std::vector<int> foo() {
    std::vector<int> temp = {1, 2, 3, 4};
    return temp;
}

std::vector<int> v = foo();

在这样的代码中,函数foo的返回值temp在内部创建然后被赋值给v,然而v获得这个对象时,会将整个temp拷贝一份,然后把temp销毁,如果这个temp非常大,这将造成大量额外的开销(这也就是传统C++一直被诟病的问题。在最后一行中,v是左值、foo()返回的值就是右值(也是纯右值

但是,v可以被别的变量捕获到,而foo()产生的那个返回值作为一个临时值,一旦被v复制后,将立即被销毁,无法获取、也不能修改。将亡值就定义了这样一种行为:临时的值能够被识别、同时又能够被移动。

右值引用和左值引用

需要拿到一个将亡值,就需要用到右值引用的申明:T &&,其中T是类型。右值引用的声明让这个临时值的生命周期得以延长、只要变量还活着,那么将亡值将继续存活。

C++11提供了std::move这个方法将左值参数无条件的转换为右值,有了它我们就能够方便的获得一个右值临时对象,例如:

Links