左值、右值及std::move详解

一、左值和右值

左值:在内存中有确定存储地址、有变量名,表达式结束后依然存在的值。左值就是非临时对象。

右值:在内存中没有确定存储地址、没有变量名,表达式结束后就会被销毁的值。右值就是临时对象。

左值引用:绑定到左值的引用,通过&来声明。

右值引用:绑定到右值的引用,通过&&来声明

例子  :

int a=10;//a是左值,10是右值
int b=a;  // 这里的b和a都是左值

int &c = a;//a是左值,左值引用
int &&d = 10;//10是右值,右值引用

ps:通常为了提升程序的性能,在传参时,使用指针和引用提高效率,减少系统的开销,引用本质上就是指针,只不过再次封装了一层,提高代码的稳定性。因为引用初始化必须要赋值,否则会报错,而指针初始化可以不用赋值但是会乱飞,虽然简单,b=a这个操作,本质上是将a先拷贝一份,然后再将值赋给b,0拷贝的做法是,直接赋值地址的,没有拷贝操作。

int a = 10;
int *b = &a;

二、智能指针资源转移(c++11)

C语言中,需要手动去转移资源,并且需要手动去释放资源:通过指针变量的拷贝,然后释放原来的指针

int* ptr1 = malloc(sizeof(int));
*ptr1 = 10;

int* ptr2 = NULL;

// 转移资源
ptr2 = ptr1;
ptr1 = NULL;

// 现在ptr2拥有这块内存,ptr1为NULL
if (ptr2 != NULL) {
    printf("%d\n", *ptr2);
    free(ptr2); // 正确释放内存
}

C++中,智能指针是c++11引入的新特性,帮助我们自动管理内存的,unique_ptr包含不能被共享的资源,智能指针对象不能拷贝但可以移动

//---------------------方法一-------------------------
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
std::unique_ptr<MyClass> ptr2;
ptr2 = std::move(ptr1); // 使用std::move将ptr1转换为右值

//---------------------方法二-------------------------
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
std::unique_ptr<MyClass> ptr2;
ptr2 = ptr1; // 使用std::move将ptr1转换为右值

方法二会在编译的时候报错,因为智能指针没有delete函数,直接拷贝编译不通过,需要使用std::move转移资源

三、本质是什么(本质是将左值转换为右值)

 如下所示,常量右值引用只能等于右值,等于左值会编译报错,需要使用std::move将左值转换成右值就不会报错了,unique_ptr也是左值的一种,需要使用move转移资源

int a = 10;            
const int a1 = 10;     
const int a2 = 20;      

//非常量右值引用
int &&b1 = a;            //错误,a是非常量左值,不能绑定到非常量右值引用
int &&b2 = a1;           //错误, a1是常量左值,不能绑定到非常量右值引用
int &&b3 = 10;           //正确,10是纯右值,可以绑定到非常量右值引用
int &&b4 = a1+a2;        //正确,(a1+a2)是纯右值,可以绑定到非常量右值引用

//常量右值引用
const int &&c1 = a;      //错误,a是非常量左值,不能绑定到常量右值引用
const int &&c2 = a1;     //错误, a1是常量左值,不能绑定到常量右值引用
const int &&c3 = a+a1;   //正确,(a+a1)是纯右值,可以绑定到常量右值引用
const int &&c4 = a1+a2;  //正确,(a1+a2)是纯右值,可以绑定到常量右值引用

//正确做法
int a = 10;                 
const int a1 = 10;        

//非常量右值引用
int &&d1 = std::move(a);     //正确,可以绑定到非常量右值引用
int &&d2 = std::move(a1);    //错误,不能绑定到非常量右值引用

//常量右值引用
const int &&c1 = std::move(a);    //正确,可以绑定到常量右值引用
const int &&c2 = std::move(a1);   //正确,可以绑定到常量右值引用

使用std::move后原来的对象就变成未知状态,如int a;这个状态,仅有分配的地址,又没存放值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值