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

1 篇文章 0 订阅
1 篇文章 0 订阅

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

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值