其他分享
首页 > 其他分享> > 左右值的概念

左右值的概念

作者:互联网

https://corecppil.github.io/CoreCpp2019/Presentations/Dan_Saks_Lvalues_and_Rvalues.pdf

简述

原版PPT 有31页,我主要摘取几个重要的点。

下面所说的对象都是广义的对象(object) 一个int float 都可以看作一个对象。而 类对象 与区分。

最后的总结是我自己总结的。

正文翻译

概览
左值

在 The C Programming Language 中,有以下的定义:

深入底层

为什么需要区分左值和右值?

继续上面的例子 n = 1

假设有这个例子 1 = n

总结:所有C 中表达式 要么是左值,要么是右值。左值和数据空间中对象相关联,右值是非左值。对于非类类型的C++ 也是正确的。但如果有类类型,就不那么准确(类对象通常不管左右值都保存在数据空间)。

其它类型

字面值:大部分字面量都是右值(1,3.2,‘c’ 等),它们不一定占用数据空间。但有些字面量(“abcdefg” 等) 却是左值,占用数据空间。

枚举常量:枚举常量也是右值。

将左值用作右值

如果是非类类型,就直接将左值视为右值。如果是类类型,将会执行左值到右值的转换。

表达式的结果

表达式例如 m + n 产生的结果存放在编译器生成的临时对象,通常存放在寄存器中。像这些的临时对象都是右值。

所以 m + 1 = n 先计算 m + 1 产生右值,向右值赋值产生错误。

再例如 &n &1 其运算对象必须是左值,因为右值和数据空间中对象无关,不可寻址。它产生的结果却是右值。

再次强调 左值是编译期的属性,如果 *p 它运算对象可以是左值,也可以是右值例如( *(p+1) ),但它返回的是左值。即使p 指向nullptr ,编译也不会出错,不过运行会出错。

在C/C++ 中,非类类型的右值不会占用数据空间。而任何类型的左值都会占用。(虽然有时候编译器会优化左值,使其不占用空间,但你应该假定左值都是占用空间)。

常对象

常对象是可寻址的对象。

编译器可能会存储常对象,也可能会优化掉(例如C 中常量是常变量,而 C++ 中会被编译器替换)

C++引用类型

掌握以上左值和右值概念有助于理解C++的引用,引用使C++ 重载运算符的行为类似于内置运算符。

引用用于关联有名对象。引用底层是常量指针,自动解引用产生左值。

enum month {
Jan, Feb, Mar, ~~~, Dec, month_end
};
typedef enum month month;
~~~
for (month m = Jan; m <= Dec; ++m) {
~~~
}

这样的代码在C 中可以正常工作,然而在C++中编译错误。内置的++ 不能用于枚举变量。

常量引用

常量引用可以绑定到非常量,也可以绑定到常量。而普通引用只能绑定非常量。

常量引用自动解引用产生不可改的左值。

类似于普通 指针,普通引用只能绑定到左值上。

常量引用既可以绑定到左值也可以绑定到右值。

const int &thr = 3; 在这种情况下,运行到这时,程序会创建一个int 临时量,其值为3。然后用thr 绑定这个临时量。当离开 thr 的范围,程序销毁这个临时量。

const double &dthr = thr; 程序先会将thr 的值转化为 double ,创建double 临时量,然后保存转化的值。之后用 dthr 绑定到这个临时量。最后,离开范围会销毁这个临时量。

右值引用

在C++ 03 中称为引用的,在C++ 11 中称为 左值引用,为了与新增的右值引用所区分。

右值引用只能绑定右值,哪怕是常右值引用。而常左值引用也可以绑定右值。

现代C++ 通常使用右值操作来避免不必要的拷贝。

与成员函数

成员函数可以用引用限定符重载,左右值调用不同版本。

总结

左右值这个概念最初是从 C 语言来的,其为了CPU 能做某些优化而设置。此时的概念是和内存中区域相关的对象都成为左值,而右值是它的补集。右值不占内存空间。右值通常都是存在 CPU 中的数据。而字面值有可能右值(‘c’),也有可能是左值(“asdfdsasd”)。

到了早期C++ (C++ 11 之前),出现了引用等。此时右值有时也占用空间(例如右值类对象)。

到了现代C++ (C++ 11及以后),出现了左值引用,右值引用的概念。为了与右值引用区分,之前的引用统称为左值引用。右值引用的出现主要是为了避免不必要的拷贝。

标签:左右,右值,对象,左值,C++,概念,引用,表达式
来源: https://www.cnblogs.com/starrys/p/13157586.html