谈一谈 C++ 中的值的类型

30 篇文章 1 订阅
9 篇文章 0 订阅

C++98

历史上,我们把值分为两类,左值 ( lvalue ) 和右值 ( rvalue )。

右值,就是只能在等号右边的值,比如字面量。

左值,就是在等号左边出现的值,当然在等号右边也能出现。

比如

a = 1; // a 是左值, 1 是右值
// 这个 1 被称作字面量

但是这样的分类方法,在遇到 const int 这样的类型时,就发现一个 const int 既不能分为左值,也不能分类为右值。(有且只有初始化时才能在等号左边出现)

所以在 C 中,左值,就是表示了一个“对象”(object) 的值,比如一个变量,一个指针等等。在 C++98 中,还把函数变成了左值。

左值的特点就是,可以绑定上左值引用。如果要引用一个右值,那引用必须是一个常引用。

int a = 100; // a 是一个左值
int &b = a; // b 是一个左值引用, 对 b 操作任何事情完全就是对 a 操作

C++11

在 C++11 中引入了一种新的语义——移动语义。具体地说,就是可以移动构造,还有移动赋值。

移动语义有点像“废物利用”一样。如果采用了移动构造,你就可以把自己身上的数据移动给新的成员,避免了不必要的数据复制。比如要移动几千个 std::string 类型的成员,C++98 中只能够复制一份再删除一份,而 C++11 中,就可以改一下 std::string 内部指针的位置,很方便。

但是要注意,只有废物才能被利用,我们给这类“废物”一个名字,就叫 xvalue,x 的意思是“将要过期的”(expiring)。原来的右值 rvalue 中细分成为了“纯右值” prvalue (pure rvalue)

所以在 C++11 中,有了三种数据类型:

lvalue

xvalue

prvalue

其中 xvalue 和 prvalue 统称 rvalue;而 lvalue 和 xvalue 统称 glvalue.

我们举一些例子。

prvalue:

字面量(除了字符串)

像 a++ 这样内置的后自增表达式(返回一个临时对象)

像 a+b 这样内置的运算、逻辑运算等

““返回一个非引用类型”的函数”的返回值

强制转换成了非引用类型

lambda 表达式

等等,更具体的分类可以看拓展阅读。

xvalue:

““返回一个右值引用”的函数”的返回值。比如 std::move(x)

强制转换了右值引用

也就是说,通过使用 std::move(x) 就可以把 x 的类型变成 xvalue,就可以调用移动构造函数了(如果实现了这个函数)。

(小提示:不要写出 return std::move(x); 这种语句,写 return x; 就行,不然会妨碍编译器优化。参考这里)

进一步,我们可以抽象出来这两个判断法则:

准则 1:能不能分辨两个表达式指的是同一个物体。比如我们可以通过比较地址。

准则 2:能不能使用移动语义。比如看看能不能用调用移动构造函数。

都满足,那就是 xvalue

满足 1 不满足 2,就是 lvalue

满足 2 不满足 1,就是 prvalue

满足 1 就统称为 glvalue,满足 2 的统称为 rvalue

分成这么多类,在绑定引用的时候就起了作用。比如不同的函数重载,一个 xvalue 优先会找右值引用,其次可能是常量左值的引用,这样就可以正确的发挥移动语义的作用了。

C++17

分类和 C++11 是一样的,但是语义上更加明确了。

glvalues:有自己地址的长寿对象

prvalues:为了初始化而用的短命对象

xvalue:资源已经不需要了,而且可以再利用的长寿对象

C++17 还引入了一些新的语法规定,有时候一个 prvalue 还可以 materialization 成 xvalue。当然,这些都不用太关心,写出问题了再说。

在我们学习的时候,经常会遇到一些问题,尤其是知识点看不懂,我的建议是,记下来,跳过去,因为编程的知识点之间的联系是非常紧密的,但是也是松散的,一个问题此路不通,我们可以换思路来解决,有的东西当下不清楚,等你把后面的知识搞定了,再回过头来觉得“原来如此”的问题是很常见的,所以不要在一个地方死磕。

最后,遇到问题多百度,多找大神问也是很重要的,建议进这个群一起聊,跟前辈一起探讨,也会得到很多帮助。也可以交流学习心得,技术问题,可以获取PDF书籍源码、教程等给大家免费使用。

f2d082717e3f46168762d845ac802313.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值