lvalue(左值)和rvalue(右值)
昨天写代码遇见一个这样的错误:{ "cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’",
代码类似下边
class MyClass {
int data;
public:
MyClass(int& e):data(e){};
};
int main(){
MyClass c(10);
return 0;
}
编译器告诉我们:“不能将非const的lvalue引用 和 rvalue绑定”,里边有两个关键词:lvalue
和rvalue
。
什么是lvalue(左值)
简单定义:内存中有确定存储地址的对象的表达式的值,可以是一个变量名:int a;
,可以是一个赋值表达式a=b
,或者字符串常量"cnblogs"
,总之,最简单鉴别的方法就是编译以下这个句子&(需要鉴别的表达式)
,能通过编译就是左值。
严格定义见:C++文档
左值有什么性质?
- 可以被取地址(&),上边我们就是用这个方法来鉴别左值。
- 可以被赋值,或者复制赋值;
//赋值 int a = 10; //复制赋值 int a(10);
- 可以初始化左值引用,也就是我们常用的引用;
int a=10; int& reference = a;
这是一些常用的性质,更多性质见:C++文档
什么是rvalue(右值)
:非左值。
常见的有字面值(除了字符串常量),后置自增自减表达式a++;a--;
右值有什么性质?
- 不能被取地址
int a = 1; int* p = &(a++); //报错,a++是右值,不能被取地址,而++a是左值
- 不能被赋值或者复制赋值
42 = 10;//很明显会报错
- 可以初始化const左值引用 ,这就是我开头程序报错的原因!我的程序没有
const
class MyClass { int data; public: MyClass(int const& e):data(e){}; //这里的形参引用用const修饰就可以编译通过了!!! }; int main(){ MyClass c(10); return 0; }
- 可以初始化右值引用;因为右值引用已经超出我的知识范畴了,以后学到再来补充。
为什么右值可以初始化const左值引用
note:下边的引用都是说左值引用
我先来说一下为什么右值不可以初始化普通引用,引用实际上是对指针的封装,主要作用是修改这个指针指向的值,那根据右值的性质:不能被取地址,所以引用和右值绑定显然是非法的。
那为什么加上const
就可以了呢?
这是因为将const引用绑定到右值时,编译器采取了一种妥协机制:编译器会为临时数据创建一个新的、无名的临时变量,并将临时数据放入该临时变量中,然后再将引用绑定到该临时变量。注意,临时变量也是变量,所有的变量都会被分配内存。所以说const
引用实际上是和右值的一个copy绑定了。
参考:https://zh.cppreference.com/w/cpp/language/value_category#cite_note-3
http://c.biancheng.net/view/vip_2254.html
原文地址:https://www.cnblogs.com/rookiezjz/p/12350050.html