C++11之右值引用

来源:互联网 发布:淘宝的a3狗粮怎么样 编辑:程序博客网 时间:2024/05/17 23:08

左值和右值的区分  

有很多认为在等号左边的就是左值,右边的就是右值,也包括我,看了这篇文章,我想,你一定会明白的,左值是指表达式结束后依然存在的持久对象,右值是指表达式结束后依然存在的持久对象,右值是指表达式结束后就不再存在的临时对象.一个区分左值与右值的便捷方法是:看能不能对表达式取地址,如果能,则为左值,否则为右值.  

int a = 12; int b = 30; int *p = &a; vector<int> vct; vctTemp.push_back(1); string str1 = "yang "; string str2 = "long"; const int &m = 10;

a和b都是持久对象(可以对其取地址),是左值。 

a+b是临时对象(不可以对其取地址),是右值. 

a++是先取出持久对象a的一份拷贝,再使持久对象a的值加1,最后返回那份拷贝,而那份拷贝是临时对象(不可以对其取地址),故其是右值.  

++a是直接在持久对象a加1,并返回那个持久对象a(可以对其取地址).故其是左值;  

vct[0]调用了重载的[],而重载了[]符号返回的类型是int &,为持久对象(可以对其取地址)。  故其是左值.  

非长量左值引用和常量左值引用

非常量左值引用只能绑定到非常量左值,不能绑定到常量左值、非常量右值和常量右值,如果允许绑定到常量左值和常量右值, 则非常量左值引用可以用于修改常量左值和常量右值,这明显违反了其常量的含义,如果允许绑定到非常量右值,则会导致非常危险的情况出现,因为非常量右值是一个临时对象,非常量左值引用可能会使用一个已经被销毁了的临时对象.   

常量左值引用可以绑定到所有类型的值,包括非常量左值,常量左值,非常量右值和常量右值.,可以看出, 使用左值引用时,我们无法区分出绑定的是否是非常量右值  

如果我们能确定某个值是一个非常量右值(或者是一个以后不再使用的左值),则我们在进行临时对象拷贝时,可以不用拷贝实际的数据,而只是“窃取”指向实际数据的指针(类似于STL中的auto_ptr,会转移所有权).c++11中引入的右值引用正好可以用于标识一个非常量右值.

右值引用根据其修饰的不同,也可以分为非常量右值引用和常量右值引用.  

非常量右值引用只能绑定到非常量右值,不能绑定到非常量左值、常量右值、和常量左值.  

来看个使用移动构造函数的例子:


#include<iostream>using namespace std;class A{private:    int data;      int *pi;public:    //禁止隐式转换    A(){    }    explicit A(int i):data(i){        cout << "normal constuctor!" << endl;        pi=&data;    }    A(const A &a)    {        data=a.data;        cout << "copy constuctor!"<<endl;        pi=&data;    }    //移动构造函数;    A(A &&a)    {        cout << "move constuctor!"<<endl;        //直接移动a.pi到pi;        pi=a.pi;        a.pi=nullptr;        a.data=0;    }   // A(A &&a)=delete;    A operator+(const A &a)    {        A temp(data+a.data);        cout << "operator+called!show temp!"<<endl;        temp.show();        cout << endl;        return temp;    }    void show() const    {        cout << "pi="<<pi<<" data=" <<data <<endl;    }};int main(int argc,char *argv[]){    int i=99;    A a(10);    a.show();    A b(i);    b.show();    A c(b);    c.show();    A d(b+c);    cout << "show d!"<<endl;    d.show();    return 0;}


运行结果:

normal constuctor!pi=0x7ffeba09dc10 data=10normal constuctor!pi=0x7ffeba09dc20 data=99copy constuctor!pi=0x7ffeba09dc30 data=99normal constuctor!operator+called!show temp!pi=0x7ffeba09dc40 data=198show d!pi=0x7ffeba09dc40 data=198


看运行结果,似乎没有调用移动构造函数,但是发现么.temp的pi地址和d的pi地址是一样的.原来编译器会帮我们自动优化的.我们显式的删除其移动构造函数.看程序是否能运行呢。

注释掉我们写的移动构造函数,去掉A(A&& a)=delete;的注释,运行结果为:

12.cpp: In member function ‘A A::operator+(const A&)’:12.cpp:45:16: error: use of deleted function ‘A::A(A&&)’         return temp;                ^12.cpp:38:5: note: declared here     A(A &&a)=delete;     ^12.cpp: In function ‘int main(int, char**)’:12.cpp:61:12: error: use of deleted function ‘A::A(A&&)’     A d(b+c);            ^12.cpp:38:5: note: declared here     A(A &&a)=delete;     ^

看结果就是说程序运行要调用A(A&& a)函数,而程序中没有这个函数。

0 0
原创粉丝点击