Rvalue Reference


右值引用专门为右值而生,可以指向右值,不能指向左值

std::move() 只将左值提升为一个右值引用,等于 static_cast<T&&> lvalue

被声明(有名字的)出来的左、右值引用都是左值

int   a = 1; // a is lvalue
int&  a_ref = a; // a_ref is a lvalue reference, which is a lvalue
int&& a_rref = std::move(a); // a_rref is a rvalue reference, which is a lvalue

但是,返回的 && 是右值

例子 std::move() 返回右值引用,但是 int&& 必须指向右值,这咉证了返回的 && 是右值。

int&& a_rref = std::move(a);

右值引用可以直接指向右值,也可以通过std::move()指向左值;而左值引用只能指向左值。

void f(const int& n) {
    n += 1; // 编译失败,const左值引用不能修改指向变量
}

void f2(int && n) {
    n += 1; // ok
}

int main() {
    f(5);
    f2(5);
}

那么右值引用是为了解决什么呢?是为了方便写“移动”语义,即所有权的转移。

如果不用右值引用,写移动语义是这样的:

    // 深拷贝赋值
    Array& operator=(const Array& temp_array) {
        ...
    }
 
    // 移动构造函数,可以浅拷贝
    Array(const Array& temp_array, bool move) {
        data_ = temp_array.data_;
        size_ = temp_array.size_;
        // 为防止temp_array析构时delete data,提前置空其data_      
        temp_array.data_ = nullptr;
    }

第一个不方便,由于必须给构造函数签名一个冗余项来重载签名,不美观。 并且,这里若用 const Array& 就没法对被移动的对像进行特定的析构操作。 还有,若用 Array& 那就没法移动一个右值。