c++11: 右值引用(right value reference)

在c++ 11之前,我们所说的引用只有左值引用,现在我们通常所说的引用也是左值引用,但是准确一点说,c++11之后,除了左值引用,还有右值引用。

在之前所谓左值就是表达式左边的值,所谓右值就是表达式右边的值,比如:

int a = 10;
//其中 a就是左值, 10就是右值
int b = a;
//其中 b是左值,a 是右值

在c++11之后,又有了明确的定义:

L-value(左值):是指可寻址的,L指的是location,Avalue (computer science)that has an address

R-value(右值):其中的R指的是Read,in computer science, a value that does not have an address in a computer language.

左值,指的是如果一个表达式可以引用到某一个对象,并且这个对象是一块内存空间且可以被检查和存储,那么这个表达式就可以作为一个左值。

右值,指的是引用了一个存储在某个内存地址里的“数据”。

上面的两个定义可以看出,左值其实要引用一个对象,而一个对象在我们的程序中又肯定有一个名字或者可以通过一个名字访问到,所以左值又可以归纳为:左值表示程序中必须有一个特定的名字引用到这个值。而右值引用的是地址里的内容,所以相反右值又可以归纳为:右值表示程序中没有一个特定的名字引用到这个值除了用地址。

理解了上面的定义之后,再理解左值引用和右值引用就好理解了,左值引用也就是我们之前所说的引用是给变量起了一个别名,而右值引用的实际上是对“数据”的引用,比如:

int a = 10;
int& b = a; //b是a 的别名
int& c = 10  //编译错误,因为 10是右值(没有变量声明)
const int& c = 10  //编译成功,对于右值的左值引用,必须是const的方式

int&& e = 10;//正确
int&& f = std::move(c);  //正确,c的地址和f的地址是一样的

int& m=a++;//错误,因为 a++会返回(10)一个新的右值,将 a值变为11,存到a里面
int&& k = a++; //正确,k和a的地址是不同的

通过上面的例子可以看出,右值引用只能绑定到将要销毁的对象上,不能绑定左值,比如:

int a = 10;
int&& c = a;//错误
int&& d = std::move(a);//正确,std::move()实际上只是做了一个类型转换而已,返回一个右值,

右值引用的作用:

1. 为了提高效率,在我们进行变量赋值的时候,有的时候会调用复制构造函数,复制构造函数往往是将对象里面保存的内容复制了一份,然后再把之前的变量销毁(析构函数),这样就花了很昂贵的代价:

class A
{
    public:
        A(int a):iA(a){}
        A(const A& a)  //复制构造函数,如果没有自己写,会默认有一个
        {
            this->ptr = a.ptr;
            this->iA = iA;
        }
        A& operator=(const A& a) //赋值函数,如果没有自己写一个覆盖,也有默认一个
        {
            this->ptr = a.ptr;
            this->iA = a.iA;
        }
        
        ~A()
        {
            ptr = nullptr;
        }
    private:
        int iA;
        object* ptr;
}

在上面的类中,

A  a;
A  b(a);  //调用复制构造函数
A&& c = std::move(a); //不会调用复制构造函数

通过右值引用,可以节约时间和空间成本。

2. 实现对象移动(std::move())

通过看std::move的源代码,就发现,实际上只是对引用对象进行了类型转换而已,并没有做实际的内存和复制操作,std::move()会返回一个右值,付给一个新的变量,最简单的实现就是swap:

//老的方式
void swap(T& a, T& b)
{
    T tmp(a);  //复制一份
    b = a;     //调用赋值函数(assignment operator),
    a = tmp;   //调用赋值函数(assignment operator)

}

//新的方式
void swap(T& a, T& b)
{
    T&& tmp = std::move(a);
    a = std::move(b);
    b = std::move(tmp);
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章