在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
我的理解
首先得知道,引用是一个左值,而常量引用是一个右值。两者最关键的地方在于,左值可以被取到地址,而右值取不到地址,这个性质就决定了右值不能在 “=” 的左侧。 对于 lValue rValue,从语言角度,我的理解是:如果是左值,那么它在当前作用域内都可以被取得,而如果是右值,那么它只能在当前一条语句中被取得。 从汇编角度类比,左值是一个内存单元里的数据,我们可以通过相对应的地址找到它,而右值是立即数或一个暂时存储在寄存器里的值。
C与C++中的左值、右值
C 中可以通过赋值号 “=” 简单地判断,比如 int a = 42; // 表达式a是左值,字面值常量42是右值 int b = 43; // 表达式b是左值,字面值常量43是右值 a = b; // 表达式a和表达式b都是左值 b = a; // 表达式a和表达式b都是左值 a = a * b; // 表达式a是左值, 表达式a*b是右值 int c = a * b; // ok,表达式c是左值,表达式a*b是右值 a * b = 42; // error,表达式a*b是右值,右值不能出现在赋值操作符的左边 //lvalue required as left operand of assignment
但是在 C++ 中,由于自定义类引入的一些新的特性,这些就没那么简单了。 当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。 C++中常见的左右值如下:
记忆方法
我的记忆规则有两条: I)左值持久,右值短暂。 左值是持久的,而右值要么是常量,要么是表达式求值所产生的临时对象。 II)一切变量都是左值,但const量是例外。
两个错误例子
例一:在递归时,用由构造函数刚构造出来的对象作为引用绑定的对象
//错误样例 int func(Object &a) { //假设 Object 有构造方法;引用需要绑定左值 if (...) return ...; return func(a(30)); //错误,a(30)是一个临时对象,是右值,而引用需要的是左值 //我觉得这儿可以沿用 C 中判断左值、右值的方法:a(30) 不能放在等号左侧,所以是右值 } //改进方法1 int func(const Object &a) { //常量引用绑定右值 if (...) return ...; func(a(30)); } //改进方法2 int func( Object &a) { if (...) return ...; Object b = a(30); // b是左值 func(b); }
例二:参数左右值匹配问题与函数类型问题 #include<iostream> using namespace std; string func1 (string &s) { string s2; return s2; } string& func2 (string &s) { string s2; return s2; //注意,其实s2不应返回,因为它是个局部变量 //这里主要是强调函数类型对左值、右值的影响 } const string func3 (string &s) { return "1234"; } int func4 (const string &s) { return 0; } int main (void) { string s1 = "123456"; // s1 是左值 string &s2 = func1(s1); //引用需要左值,而 func1() 非引用类型,它返回的是右值,所以错误 string &s3 = func2(s2); //引用需要左值,由于 func2() 为引用类型,它返回的是左值,所以编译器通过 string &s4 = func3(s1); // func3()返回的是右值,而 s3需要的是左值,所以出错 func4(s1); // 标准规定不论是左值还是右值都可以转化成常量引用,所以正确 return 0; }
因为常量引用不仅可以接收普通引用和常量引用,而且还表明了函数不能修改它实参的值,利于访问控制,所以把函数不会改变的形参定义为常量引用是一个很好的习惯。
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论