一.举例理解(可跳过)
定义
左值:一个稳固的房子(有名字)
右值:没有名字的危房
属性
左值拥有左值属性和右值属性
左值属性:是指他的房子名字
右值属性:是指房子里住的人,即对象值
例如 int a=1;
a有名字,它的名字是a,1没有名字(只有值),那么a为左值,1为右值
房子0x001名字为a,住着1,那么结果仍然是左值(有名字的房子即左值)
二.左值和右值
1. 定义
左值(lvalue: locator value):存储在内存中,有明确存储地址(可寻址)的数据
右值(rvalue: read value):提供数据值的数据(不一定可以寻址,可能存在寄存器中)
判断方法:
有名称,能获取到地址的值就为左值,不能的就是右值
2. 左值引用
定义:能指向左值,不能指向右值的就为左值引用
int x=5;
int & ref=x;//左值引用指向左值
int & reb=4;//报错,左值引用指向右值
3. 右值引用
定义:可指向右值,不能指向左值
int &&ref=5;//不报错
int a=5;
int &&reb=a;//报错,不能指向左值
&&理解
&&为右值引用的声明符号,允许绑定到临时对象上(即危房上)
底层实现原理:(以int &&a=10;举例)
- 编译阶段,编译器将int &&a解析为右值引用类型的变量a;
- 初始化阶段,10作为右值赋值给a;
- 内存中,a被分配一个地址,并将该地址指向存储值为10的临时对象
int main(){
int &&a = 1;//右值引用,a为左值
int b=10;//左值
int &&b1=b;//报错,不能将左值转化为右值引用
}
4. move函数作用
上面提到,不能将左值转化为右值引用(右值引用指向左值),那什么方式可以实现呢?
可以调用move来实现
int b=10;
int &&b1=std::move(b);
原理:
move告诉编译器,我们有一个左值,但是我希望像右值一样处理它
调用move意味着承诺:除了对b赋值或销毁外,我们将不使用它。
使用场景
用于STL和自定义类中实现移动语义 ,避免拷贝。
- STL实现
int main(){
string str1="feifei";
vector<string> vec;
vec.push_back(str1);
vec.push_back(std::move(str1));//避免str1失去原有值,变成空字符串
vec.emplace_back(std::move(str1));//str1失去原有值
vec.emplace_back("felix");
}
void push_back(const value_type& val);
void push_back(value_type&& val);
void emplace_back(Args&&... args);
- 自定义实现
class AY{
public:
....
AY(AY&&temp_ay){
data1=temp_ay.data1;
size1=temp_ay.size1;
temp_ay.data1=nullptr;
}
int *data1;
int size1;
}
int main(){
AY a;
....
AY b(std::move(a));
}
这些就涉及深拷贝浅拷贝问题了,可以通过移动构造函数实现,移动构造函数具体实现方式可参考
https://blog.csdn.net/weixin_44788542/article/details/126284429
5. const引用
C++ 允许常量引用(const 引用)来绑定到临时的右值(包括整数常量)上
int main(){
int && a=1;
int *c=3;//报错
const int &f =3;//不报错,const为保护罩,将对象保护起来
const int b=100;
int &b2=b;//报错 非常量左值引用不支持引用常量左值
实现原理:
int & a=1;//报错 原因:1为立即数,存放在寄存器中,执行完就被销毁
const int &a=1;//不报错
//原因:内存中产生一个临时变量,a引用这个临时变量,在整个 a 的作用域内,临时对象将继续存在,直到 a 的作用域结束。
//相当与
const int b =10;
const int &a=b;
三. 延伸
const 和&的关系
int a=10;
int &b =a;
b=20;
//等同于
int a=10;
int * const b=&a;
*b=20;
auto &&是万能引用
&&不是右值引用吗,为什么可以引用左值?
原因在于auto;
auto 关键字推导变量类型时,如果变量被初始化为一个右值,auto 推导出的类型是右值引用;而当变量被初始化为一个左值时,auto 推导出的类型是左值引用。
通过下面这个例子就很好理解了
int x = 5;
auto &&ref1 = x; // 推导为 int&
auto &&ref2 = 5; // 推导为 int&&
上面很多都是概念知识,具体应用可参考下面博文,强推!!!
https://sxyandqx.blog.csdn.net/article/details/130955297
参考鸣谢
https://www.bilibili.com/video/BV1LY4y1F7Jn
https://blog.csdn.net/jiexianxiaogege/article/details/133106476
c++ primer(第五版)
https://zhuanlan.zhihu.com/p/335994370