深入理解(实例) -- c++ 右值引用 左值引用

来源:互联网 发布:淘宝 店招 css 编辑:程序博客网 时间:2024/06/16 02:15

c++ 右值引用 左值引用

下面代码 看出右值引用 跟左值引用的相似之处,都具有别名的左右,可以与它引用的变量共同修改地址内的内容
左值/右值引用可以延长临时变量的寿命,直到该右值引用的寿命结束才析构
右值引用可以直接引用临时变量(如常量 1 ,3.1等),且可以对它进行修改(不指定const)
左值引用一般不会用于引用临时变量,虽然通过一些手段可以编译成功,但不安全也没有意义

struct RefTest{    RefTest()    {        str = "constructor";    }    ~RefTest()    {        str = "destructor";        std::cout<<str.c_str()<<" ~RefTest"<<std::endl;    }    std::string&& getrvalue_ref() &&    {        return std::move(str);    }    std::string& getlvalue_ref()    {        return (str);    }    std::string str;};void test1(){    RefTest a;    RefTest&& b = std::move(a);    std::cout<<a.str.c_str()<<"\t"<<b.str.c_str()<<std::endl;    a.str = "change";    std::cout<<a.str.c_str()<<"\t"<<b.str.c_str()<<std::endl;//constructor   constructor//  change  change//    int& c = 3; //不能编译通过,右边是右值    int&& c = 3;    c++;    std::cout<<c<<"\t"<<std::endl;//4    RefTest(); //立即析构//  destructor ~RefTest    RefTest&& d = RefTest(); //函数结束后析构    d.str = "change";    std::cout<<d.str.c_str()<<std::endl;//  change    std::string&& e = RefTest().getrvalue_ref();    std::cout<<e.c_str()<<"\t"<<std::endl;    e = "change";    std::cout<<e.c_str()<<"\t"<<std::endl;//  destructor ~RefTest//  destructor//  change    std::string& f = RefTest().getlvalue_ref();    std::cout<<f.c_str()<<"\t"<<std::endl;    f = "change";    std::cout<<f.c_str()<<"\t"<<std::endl;//  destructor ~RefTest//  destructor//  change//  destructor ~RefTest//  destructor ~RefTest}

对于函数的返回值如果是临时变量(函数内建的变量,既不是参数变量也不是类成员变量),不能返回引用!
对c++ 在编译的时候会对返回值进行优化,如果返回的是临时变量(注意不是引用!),则会直接使用该临时变量的地址,不会进行内容的迁移和内参的释放,因此效率比较高。这也说明返回值处一般不需要使用move来强制转换右值,多此一举。

int getrvalue(){    return 2;}int& getlvalue_ref(){    int a = 3;    return a;}struct Rvaluetest{    Rvaluetest(int i):str(new char[15])    {        value = i;        str[0] = 'c';        str[1] = 0;        cstr = "test";    }    ~Rvaluetest()    {        value = 0;        std::cout<<" ~Rvaluetest "<<cstr.c_str()<<std::endl;        delete str;    }    int value = 2;    char * const str;    std::string cstr;};Rvaluetest&& getrvalue_ref(){    Rvaluetest a(5);    return std::move(a);}Rvaluetest getrvalue_test(){    Rvaluetest a(5);    return (a);}void RefTest(){//  int& c =  getrvalue();  //error invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’    const int& c =  getrvalue();    std::cout<<c<<"\t"<<std::endl;//  2    int&& d =  getrvalue();    d++;    std::cout<<d<<"\t"<<std::endl;//  3    int& e = getlvalue_ref();  //编译能通过 但 再次调用该变量会出现 Segmentation fault//  std::cout<<e<<"\t"<<std::endl;  //Segmentation fault    Rvaluetest&& f = getrvalue_ref();    std::cout<<++f.value<<"\t"<<f.str<<" "<<f.cstr.c_str()<<std::endl;    //乱码,说明运行了析构函数,因此虽然能够编译通,并能够运行,但是不安全    //右值引用终究还是引用,他并没有对内存的释放权,如果它引用的内存寿命短暂,可能会出错// ~Rvaluetest test//  1    �$���    Rvaluetest g = getrvalue_test();  //因为c++ 编译器的优化,该函数内建的临时变量并没有运行析构函数,而是整体通过返回值返回转移到g,寿命延长                                      //函数的返回值是右值,这也说明,c++中右值的赋值是直接地址赋值,并没有内容的迁移和内参释放,高效    std::cout<<++g.value<<"\t"<<g.str<<" "<<g.cstr.c_str()<<std::endl;//  6   c test// ~Rvaluetest test}
原创粉丝点击