C++11左值和右值、左值引用和右值引用浅析

news/2024/12/23 2:25:59/

从字面意思来讲,左值就是“能用在赋值语句等号左侧的内容(它得代表一个地址)”;右值就是不能作为左值的值,即右值不能出现在赋值语句中等号的左侧。C++中的一条表达式,要么就是右值,要么就是左值,不可能两者都是。但是一个左值有时候又能被当做右值使用(即这个对象具有右值属性,但并不是右值)。如 i = i+1这条语句:对象i在赋值语句等号的右侧时,用的是这个对象的值(具有右值属性),这个对象在赋值语句左侧时,用的是对象在内存中的地址(具有左值属性)。所以一个对象可以同时具有左值和右值属性^{[1]}

赋值运算符左侧的对象就是一个左值,但实质上整个赋值语句的结果仍然是左值,只不过在使用printf函数或者cout等场景进行输出的时候被当做右值使用(即左值具有右值属性)。

在左值表达式和右值表达式中,不要被“表达式”三个字所迷惑,如一个变量也可以称之为表达式、因此可以这样理解,左值表达式就是左值,右值表达式就是右值^{[1]}

左值引用(绑定到左值):引用那些希望改变值的对象,左值引用带一个"&"。

右值引用(绑定到右值):首先它也是一个引用,但是右值引用所侧重表达的意思往往是表示所引用对象的值在使用之后就无需保留了(如临时变量),右值引用带有两个“&&”。

左值引用就是绑定到左值的引用,右值引用就是绑定到右值的引用。一般来讲,右值引用其实主要是用来绑定到那些“即将销毁/临时的对象”上。右值引用也是引用。并且,右值引用虽然绑定到了右值对象上,但是右值引用本身还是个左值,毕竟右值引用也是位于等号左边的,如下代码是可以正常编译通过的。

#include <bits/stdc++.h>using namespace std;int main()
{int i = 1;int &&r1 = i++; // r1虽然是个右值引用,引用到了右值对象,但是r1本身还是个左值int &r5 = r1;   // 可以,说明r1本身是一个左值cout << r5 << endl;return 0;
}

返回左值引用的函数,连同赋值、下标、解引用和前置递增递减运算符等等,都是返回左值表达式(左值)的例子,因此可以讲一个左值引用绑定到这类表达式的结果上。

返回非引用类型的函数,连同算术、关系、位以及后置递增运算符,都生成右值,不能将一个左值引用绑定到这类表达式上,但是可以将一个const的左值引用或者一个右值引用绑定到这类表达式的结果上。

所有变量都要看成是左值,因为他们是有地址的,这类变量用右值绑定也绑定不上。

任何函数里的形参都是左值,即使在诸如“void (int &&)”这种写法里面,形参w的类型是右值引用(需要绑定到右值上),但是w本身还是一个左值。

右值引用引入的目的是提高程序运行的效率问题,,其手段是把复制对象操作变成移动对象操作

移动对象的概念如下:假设对象A不再使用了,那么就可以把对象A里面一些使用new分配的内存卡的所有权转给对象B,对于对象B而言,就不用再new出一些内存块了。把A种new出来的内存块直接转给B后,A 就把指向这些内存卡的指针清空一下。这就叫移动对象(把老对象里面的一些对象转移给了新对象)。也就是说,很多分配出去的内存并没有被回收而是转移给了新对象,这种把某一些内存块从原来的对象A转移给了新对象的操作就叫做移动

对象的移动操作是通过移动构造函数和移动赋值运算符来实现的,移动构造函数和移动赋值运算符的外观看起来与拷贝构造函数和复制运算符非常像,只不过移动构造函数和移动赋值运算符所需要的参数类型是“&&”这种右值引用类型

std::move函数虽然翻译成中文是移动的意思,但是这个函数实际上并没有做任何移动操作,而是把一个左值强制转换成右值(带来的结果就是一个右值引用可以绑定到这个转换得到的右值上面去了)。本来一个右值引用是无法绑定到左值上去的,但是经过move函数处理之后(将左值进行转换得到右值),这个右值引用就能绑定到原来的一个左值上面去了。有些函数的参数是一个右值引用,需要绑定到右值,此时也可以用move函数将左值转换成右值,转换结果就可以当做实参传递给该函数了。

通常情况下,如果需要移动语义,程序员必须自定义移动构造函数。当然对于一些简单的、不包含任何资源的类型来说,实现移动语义与否都无关紧要,因为对于这样的类型而言,移动就是拷贝,拷贝就是移动。移动语义往往构造的是资源型的类型,如智能指针,指针、文件流等

对于移动构造函数而言,抛出异常是件危险的事情。因为移动语义还没完成,一个异常却抛出来了,这可能会导致一些指针成为悬挂指针。因此程序员应当尽量编写不抛出异常的移动构造函数:通过为其添加一个noexcept关键字,可以保证移动构造函数抛出的异常会直接调用terminate终止程序运行而不是造成指针悬挂的问题^{[2]}

[1]《C++新经典》,王建伟编著

[2]《深入理解C++11:C++11新特性解析与应用》,IBM XL编译器开中国开发团队著


http://www.ppmy.cn/news/901818.html

相关文章

Windows上 万能的串口调试助手

之前自己找了很久的串口调试助手&#xff0c;还自己去编写&#xff0c;现在发现了一个非常好用的串口工具&#xff1a;ScriptCommunicator。 这是一个开源软件&#xff0c;功能强大。 ScriptCommunicator软件下载地址&#xff1a;https://github.com/szieke/ScriptCommunicat…

漏洞复现-CVE-2023-33246 Apache RocketMQ RCE漏洞原理与复现

目录 漏洞原理漏洞描述影响范围 Apache RocketMQ学习文档学习代码审计 漏洞复现docker环境搭建exp代码 总结参考 漏洞原理 漏洞描述 For RocketMQ versions 5.1.0 and below, under certain conditions, there is a risk of remote command execution. Several components of…

修复漏洞(二)离线升级Tomcat版本

前言 生产环境无法联网&#xff0c;只能通过下载离线版本更新Tomcat到小版本最新注意Tomcat10和11与jdk1.8都不兼容&#xff0c;只能更新到小版本的最新前提是按照我这种方法配置Tomcat开机自启的https://blog.csdn.net/qq_44648936/article/details/130022136 步骤 备份整个…

软件整理

一、 https://www.microsoft.com/zh-CN/download/details.aspx?id3702 下载虚拟pc。安装后&#xff0c;全部下一步&#xff0c;最后&#xff0c;右击虚拟pc&#xff0c;设置&#xff0c;在光驱里面选中你的iso文件。这样就可以安装一个虚拟的pc端。 还有修改mac的方法。 在打开…

从零开始整合spingMVC

111 转载于:https://www.cnblogs.com/doublekiller/p/5743233.html

可以清理掉重复文件的PC软件

下载并使用DoubleKiller进行重复文件的清理。

重复文件清理绿色工具——DoubleKiller

小巧实用的重复文件清理绿色工具——DoubleKiller DoubleKiller Pro Download

10个增强Windows效率的必备免费软件

几乎每台电脑都装有windows系统&#xff0c;因此我们每天都对硬盘里的文件进行复制&#xff0c;粘贴&#xff0c;创建&#xff0c;移动&#xff0c;删除等等。windows本身的操作工具&#xff0c;例如简单的复制粘贴功能&#xff0c;简陋的资源管理器&#xff0c;都不能满足高效…