r-value(Rvalue) 和l-value(Lvalue)

作者在写引用类型与指针比较随笔时进行代码试验,发现编译错误引出对l - value(左值)的思考。经探究,左值在赋值时位于“=”左边,必须引用某个对象,右值是具体数值。还介绍了左值和右值使用的几个要点,如右值不能转左值等。
部署运行你感兴趣的模型镜像

        在写引用类型与指针的比较这篇随笔的时候,我写了一些试验性的代码以检验一些结论是否正确。
        首先,引用是一个const的指针(注意不是指向const object的指针),所以在声明一个引用的同时必须对这个引用进行初始化。因此

None.gif int   & b;

编译不能通过是自然而然的事情,错误信息是:references must be initialized。多事的我就想,既然是const的指针,那我能不能这么写呢:

None.gif int   *   const  b; 

结果错误信息变成了const object must be initialized if not extern。接着我再给这个statement加了个extern。OK,编译错误没有再出现了,接着,我给这个指针进行赋值。结果出现了这样的编译错误:
        l-value specifies const object

        到此为止,我看到了一个似懂非懂的东西l-value。 到底什么是l-value呢?我第一时间想到左结合了,譬如说"hello" + "world" + "!" 等价于("hello" + "world") + "!"。由此推广,我可以想到的左值的一个解释就是:在赋值的时候,"="运算符左边的就是左值了。
        而事实上,我的猜测也是基本正确的。左值必须引用于某个对象,而对于赋值运算符,它的左操作数必须是一个左值(lvalue expression must refer to an object.For the assignment to be valid, the left operand must refer to an object-it must be an lvalue. [1] );而右值(rvalue)则是具体的数字型或是字符型的值(Every expression is either an lvalue or an rvalue." So an rvalue is any expression that is not an lvalue. [1])。
      
        以下是对于左值和右值在使用上的几个要点:
        1、右值是不能转化为左值的,而反过来,则是可以的。如:    

None.gif int  a, b;
None.gif
=  b;
None.gif

              a和b都是左值,但是b出现在了赋值运算符的右边。编译器在编译过程中做了左值到右值的转换。    
        2、"+"运算符的操作数没有左值或是右值的限制,但是运算的结果却是右值。比如说:

None.gif (m  +   1 =  n;

              是会发生编译错误的,因为m + 1是右值;
        3、"&"运算符的操作数必须是左值,而结果也是右值(注意这是取址运算符哦,别跟引用搞混了);
        4、"*"运算符的操作数则左值或着右值,其结果则是左值,如

None.gif int  a  =   2 ;
None.gif
int   * =   new   int [ 3 ];
None.gif
* =  a;
None.gif
* (p + 1 =   3 ;

       [1] Lvalues and Rvalues

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

### 关于右值用作左值的场景或解决相关错误 在编程中,将右值用作左值是一种常见的错误,尤其是在涉及变量赋值、函数调用或表达式操作时。右值(rvalue)通常是指临时对象或常量值,而左值(lvalue)则指具有持久存储地址的对象。以下是一些可能的场景以及解决方法: #### 1. 变量赋值中的错误 在 C++ 中,尝试将右值赋值给另一个右值会导致编译错误。例如: ```cpp int x = 5; x + 3 = 10; // 错误:x + 3 是一个右值,不能作为左值使用[^1] ``` 这种错误可以通过重新设计代码逻辑来避免。例如,可以将结果存储到一个新的变量中: ```cpp int x = 5; int result = x + 3; // 正确:result 是左值 result = 10; // 正确:result 是左值 ``` #### 2. 函数返回值的错误 如果函数返回的是一个临时对象(右值),则不能直接将其用作左值。例如: ```cpp int getValue() { return 42; } getValue() = 10; // 错误:getValue() 返回的是右值,不能作为左值使用[^1] ``` 为了解决这个问题,可以将返回值存储到一个变量中,然后再进行操作: ```cpp int value = getValue(); // 正确:value 是左值 value = 10; // 正确:value 是左值 ``` #### 3. 引用绑定中的错误 在某些情况下,可能会尝试将右值绑定到非 const 引用。例如: ```cpp void modify(int& ref) { ref = 10; } modify(5); // 错误:5 是右值,不能绑定到非 const 引用[^1] ``` 为了解决这个问题,可以使用 `const` 引用来绑定右值: ```cpp void observe(const int& ref) { std::cout << ref << std::endl; } observe(5); // 正确:5 是右值,可以绑定到 const 引用 ``` #### 4. 移动语义与右值引用 C++11 引入了右值引用移动语义,允许更高效地处理右值。例如: ```cpp std::vector<int> createVector() { return std::vector<int>{1, 2, 3}; } std::vector<int> vec = createVector(); // 使用移动语义,避免深拷贝[^2] ``` 通过右值引用,可以显式地处理右值: ```cpp void consume(std::vector<int>&& vec) { // 消费 vec 的资源 } consume(createVector()); // 正确:createVector() 返回的是右值 ``` #### 5. 初始化数组时的右值问题 在初始化数组时,如果字符串常量的长度超过了数组的容量,可能导致右值无法正确绑定。例如: ```cpp char a[3] = "abc"; // 错误:字符串常量 "abc" 包含隐式的 NUL 字符,超出数组容量 ``` 为了解决这个问题,可以手动指定数组元素: ```cpp char a[3] = {'a', 'b', 'c'}; // 正确:明确指定数组元素 ``` ### 示例代码 以下是一个综合示例,展示了如何正确处理右值左值: ```cpp #include <iostream> #include <vector> // 函数返回右值 std::vector<int> createVector() { return std::vector<int>{1, 2, 3}; } int main() { // 使用移动语义处理右值 std::vector<int> vec = createVector(); // 正确:使用移动语义 // 将右值存储到左值 int value = 5; // 正确:value 是左值 value = 10; // 正确:value 是左值 // 绑定右值到 const 引用 const int& ref = 5; // 正确:5 是右值,可以绑定到 const 引用 return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值