c++学习笔记(13)-左值和右值

news2024/11/18 17:51:28

一、左值与右值

  • 啥是左值和右值呢?

左值:在内存有确定存储地址、有变量名,表达式结束依然存在的值,简单来说左值就是非临时对象。
右值:就是在内存没有确定存储地址、没有变量名,表达式结束就会销毁的值,简单来说右值就是临时对象。

int a = 0;  // 在这条语句中,a 是左值,0 是临时值,就是右值。

左值可以分为两类:常量左值 和 非常量左值

int a=10;              	// a 为非常量左值(有确定存储地址,也有变量名)
const int a1=10;      //a1 为常量左值(有确定存储地址,也有变量名)
const int a2=20;      //a2 为常量左值(有确定存储地址,也有变量名)

同理,右值也可以分为两类:常量右值 和 非常量右值

int a=10;              	// 10 为非常量右值
const int a1=10;      
const int a2=20;      
a1+a2               	// (a1+a2) 为常量右值

二、左值引用于右值引用

  • 知道了左值与右值了,那啥是左值引用与右值引用呢?

  • 左值引用:其实就是绑定到左值的引用,通过&来获得左值引用。

    • 左值引用举例
int a=10;              //非常量左值(有确定存储地址,也有变量名)
const int a1=10;       //常量左值(有确定存储地址,也有变量名)
const int a2=20;       //常量左值(有确定存储地址,也有变量名)
 
//非常量左值引用
int &b1=a;            //正确,a是一个非常量左值,可以被非常量左值引用绑定
int &b2=a1;           //错误,a1是一个常量左值,不可以被非常量左值引用绑定
int &b3=10;           //错误,10是一个非常量右值,不可以被非常量左值引用绑定
int &b4=a1+a2;        //错误,(a1+a2)是一个常量右值,不可以被非常量左值引用绑定

//常量左值引用
const int &c1=a;      //正确,a是一个非常量左值,可以被非常量右值引用绑定
const int &c2=a1;     //正确,a1是一个常量左值,可以被非常量右值引用绑定
const int &c3=a+a1;   //正确,(a+a1)是一个非常量右值,可以被常量右值引用绑定
const int &c4=a1+a2;  //正确,(a1+a2)是一个常量右值,可以被非常量右值引用绑定

总结归纳:非常量左值引用只能绑定到非常量左值上;常量左值引用可以绑定到非常量左值、常量左值、非常量右值、常量右值等所有的值类型

  • 右值引用:其实也是绑定到右值的引用,通过&&来获得右值引用。

    • 左值引用举例:
int a=10;             //非常量左值(有确定存储地址,也有变量名)
const int a1=20;      //常量左值(有确定存储地址,也有变量名)
const int a2=20;      //常量左值(有确定存储地址,也有变量名)

//非常量右值引用
int &&b1=a;            //错误,a是一个非常量左值,不可以被非常量右值引用绑定
int &&b2=a1;           //错误,a1是一个常量左值,不可以被非常量右值引用绑定
int &&b3=10;           //正确,10是一个非常量右值,可以被非常量右值引用绑定
int &&b4=a1+a2;        //错误,(a1+a2)是一个常量右值,不可以被非常量右值引用绑定

//常量右值引用
const int &&c1=a;      //错误,a是一个非常量左值,不可以被常量右值引用绑定
const int &&c2=a1;     //错误,a1是一个常量左值,不可以被常量右值引用绑定
const int &&c3=a+a1;   //正确,(a+a1)是一个非常量右值,可以被常量右值引用绑定
const int &&c4=a1+a2;  //正确,(a1+a2)是一个常量右值,不可以被常量右值引用绑定

总结归纳:非常量右值引用只能绑定到非常量右值上;常量右值引用可以绑定到非常量右值、常量右值上。
image.png
从上述可以发现,常量左值引用可以绑定到右值上,但右值引用不能绑定任何类型的左值,若想利用右值引用绑定左值该怎么办呢?

  • C++11中提供了一个标准库move函数获得绑定到左值上的右值引用,即直接调用std::move告诉编译器将左值像对待同类型右值一样处理,但是被调用后的左值将不能再被使用。
  • std::move()函数举例
int a=10;                 //非常量左值(有确定存储地址,也有变量名)
const int a1=20;          //常量左值(有确定存储地址,也有变量名)

//非常量右值引用
int &&d1=std::move(a);    //正确,将非常量左值a转换为非常量右值,可以被非常量右值引用绑定
int &&d2=std::move(a1);    //错误,将常量左值a1转换为常量右值,不可以被非常量右值引用绑定

//常量右值引用
const int &&c1=std::move(a);      //正确,将非常量左值a转换为非常量右值,可以被常量右值引用绑定
const int &&c2=std::move(a1);     //正确,将常量左值a1转换为常量右值,可以被常量右值引用绑定

最后可以发现,编译器利用std::move将左值强制转换为相同类型的右值之后,引用情况跟右值是一模一样的。

三、右值引用与左值引用的区别

  • 1、左值引用绑定到有确定存储空间以及变量名的对象上,表达式结束后对象依然存在;
  • 2、右值引用绑定到要求转换的表达式、字面常量、返回右值的表达式等临时对象上,赋值表达式结束后就对象就会被销毁。
  • 3、左值引用后可以利用别名修改左值对象;右值引用绑定的值不能修改

四、引入右值引用的原因

  • 1、替代需要销毁对象的拷贝,提高效率:某些情况下,需要拷贝一个对象然后将其销毁,如:临时类对象的拷贝就要先将旧内存的资源拷贝到新内存,然后释放旧内存,引入右值引用后,就可以让新对象直接使用旧内存并且销毁原对象,这样就减少了内存和运算资源的使用,从而提高了运行效率;
  • 2、移动含有不能共享资源的类对象:像IO、unique_ptr这样的类包含不能被共享的资源(如:IO缓冲、指针),因此,这些类对象不能拷贝但可以移动。这种情况,需要先调用std::move将左值强制转换为右值,再进行右值引用。
class MyString {
private:
	char* _data;
	size_t   _len;
	void _init_data(const char *s) {
		_data = new char[_len + 1];
		memcpy(_data, s, _len);
		_data[_len] = '\0';
	}
public:
	MyString() {
		_data = NULL;
		_len = 0;
	}

	MyString(const char* p) {
		_len = strlen(p);
		_init_data(p);
	}

	MyString(const MyString& str) {
		_len = str._len;
		_init_data(str._data);
		std::cout << "Copy Constructor is called! source: " << str._data << std::endl;
	}

	MyString& operator=(const MyString& str) {
		if (this != &str) {
			_len = str._len;
			_init_data(str._data);
		}
		std::cout << "Copy Assignment is called! source: " << str._data << std::endl;
		return *this;
	}

	virtual ~MyString() {
		if (_data != NULL) {
			std::cout << "Destructor is called! " << std::endl; 
			free(_data);
		}
	}
};

int main() { 
	MyString a; 
	a = MyString("Hello"); 
	std::vector<MyString> vec; 
	vec.push_back(MyString("World")); 
}

运行结果:

Copy Assignment is called! source: Hello
Destructor is called!
Copy Constructor is called! source: World
Destructor is called!
Destructor is called!
Destructor is called!

总共执行了2次拷贝,MyString(“Hello”)和MyString(“World”)都是临时对象,临时对象被使用完之后会被立即析构,在析构函数中free掉申请的内存资源。 如果能够直接使用临时对象已经申请的资源,并在其析构函数中取消对资源的释放,这样既能节省资源,有能节省资源申请和释放的时间。 这正是定义转移语义的目的。
通过加入定义转移构造函数和转移赋值操作符重载来实现右值引用(即复用临时对象):

MyString(MyString&& str) { 
		std::cout << "Move Constructor is called! source: " << str._data << std::endl; 
		_len = str._len; 
		_data = str._data; 
		str._len = 0; 
		str._data = NULL;   // ! 防止在析构函数中将内存释放掉
	}

	MyString& operator=(MyString&& str) { 
		std::cout << "Move Assignment is called! source: " << str._data << std::endl; 
		if (this != &str) { 
			_len = str._len; 
			_data = str._data; 
			str._len = 0; 
			str._data = NULL;  // ! 防止在析构函数中将内存释放掉
		} 
		return *this; 
	}

运行结果:

Move Assignment is called! source: Hello
Move Constructor is called! source: World
Destructor is called!
Destructor is called!

需要注意的是:右值引用并不能阻止编译器在临时对象使用完之后将其释放掉的事实,所以转移构造函数和转移赋值操作符重载函数 中都将_data赋值为了NULL,而且析构函数中保证了_data != NULL才会释放。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1338371.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1764程控直流电源

1764程控直流电源 交流输入电压范围&#xff1a;100&#xff5e;242Vac 在自动测试环境中提供偏置和对部件或最终产品提供激励的理想设备 国产思仪电源 01 产品综述 1764程控直流电源是在自动测试环境中提供偏置和对部件或最终产品提供激励的理想设备。其广泛应用于民用测…

无线路由器DHCP导致网络故障一例

多个DHCP故障 这几天公司网络很难用&#xff0c;也不知道原因。通过路由器的检测功能&#xff0c;领导截图如下&#xff1a; 故障解决 其实解决办法也很简单&#xff0c;就是关闭设备排查。结果发现是一个无线路由器导致的。进入路由器管理界面&#xff0c;关闭DHCP即可。 反思…

SAP PP BAPI 成本收集器的操作

成本收集器常见用tcode:KKF6n 删除标记也是在这里操作 那业务提出批量打删除标记的事务代码却是没有&#xff0c;预研一下 SAP 关于成本收集器的BAPI KOSA KK_F_PKOSA_AUTHORITY KK_F_PKOSA_COPY KK_F_PKOSA_CREATE KK_F_PKOSA_DISPLAY KK_F_PKOSA_FILL KK_F_PKOSA_FIND KK…

华为——使用ACL限制内网主机访问外网网站示例

组网图形 图1 使用ACL限制内网主机访问外网网站示例 ACL简介配置注意事项组网需求配置思路操作步骤配置文件 ACL简介 访问控制列表ACL&#xff08;Access Control List&#xff09;是由一条或多条规则组成的集合。所谓规则&#xff0c;是指描述报文匹配条件的判断语句&#…

如何使用iframe嵌套跨域类型的网址?

本章教程&#xff0c;主要介绍一下&#xff0c;如何利用iframe嵌套一些存在跨域性的问题。 这里我们以百度首页网址进行举例说明。 如果我们直接嵌套百度的首页地址&#xff0c;如下 <!DOCTYPE html> <html lang"en"><head><meta charset"…

基于 OV2640 的以太网 RGMII 图像传输系统设计

相关文章: (1)千兆以太网网络层 ARP 协议的原理与 FPGA 实现 (2)千兆以太网硬件设计及链路层 MAC 协议格式 (3)CRC校验原理及实现 (4)RGMII 与 GMII 转换电路设计 (5)千兆以太网网络层 IP 协议介绍与 IP 校 验和算法实现 (6)千兆以太网传输层 UDP 协议原理与 FPGA…

楼宇对讲门铃的芯片选型分析

目前很多的高层住宅都使用了对讲门铃了&#xff0c;在频繁使用中&#xff0c;门铃会出现的越来越多种类&#xff0c;下面我就简单的介绍会有用到的几款芯片. 语音通话芯片&#xff1a;D34018,D34118,D5020,D31101; D34018 单片电话机通话电路&#xff0c;合并了必 需的放大器…

Postman接口测试(附教程)

前言 之前还没实际做过接口测试的时候呢&#xff0c;对接口测试这个概念比较渺茫&#xff0c;只能靠百度&#xff0c;查看各种接口实例&#xff0c;然后在工作中也没用上&#xff0c;现在呢是各种各样的接口都丢过来…

C++力扣题目347--前k个高频元素

给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2]示例 2: 输入: nums [1], k 1 输出: [1] 提示&#xff1a; 1 < nums.length < 105k 的取…

uniapp中uview的text组件

基本使用&#xff1a; 通过text参数设置文本内容。推荐您使用:textvalue的形式 <u--text text"我用十年青春,赴你最后之约"></u--text>设置主题&#xff1a; 通过type参数设置文本主题&#xff0c;我们提供了五类属性。primary error success warning…

Maven之插件入门

官方文档&#xff1a;https://maven.apache.org/guides/plugin/guide-java-plugin-development.html 命名规范 <yourplugin>-maven-plugin 创建项目 生成项目 方式一、IDEA 2023 方式二、命令行 mvn archetype:generate -DgroupIdcn.lsj -DartifactIdhello-maven-pl…

【EI会议征稿通知】第五届电子商务与互联网技术国际学术会议(ECIT 2024)

2023 4th International Conference on E-Commerce and Internet Technology 第五届电子商务与互联网技术国际学术会议(ECIT 2024) 电子商务是以信息网络技术为手段&#xff0c;以商品交换为中心的商业活动。在互联网开放的网络环境下&#xff0c;基于客户端/服务端应用方式&…

微信小程序添加用户隐私保护指引

微信小程序添加用户隐私保护指引 一、官方介绍二、实现效果三、实现步骤privacyPopup.jsprivacyPopup.wxmlprivacyPopup.jsonprivacyPopup.wxss首页的index.wxml首页的index.js首页的index.json 四、配置隐私协议请求参数效果 前段时间不知道大家有没有发现很多小程序都添加了用…

AlignBench:量身打造的中文大语言模型对齐评测

对齐&#xff08;Alignment&#xff09;&#xff0c;是指大语言模型&#xff08;LLM&#xff09;与人类意图的一致性。换言之&#xff0c;就是让LLM生成的结果更加符合人类的预期&#xff0c;包括遵循人类的指令&#xff0c;理解人类的意图&#xff0c;进而能产生有帮助的回答等…

Python小工具——开发一个加密解密的小应用 windows下可执行文件exe制作

前言 本篇博客是python开发的使用案例博客&#xff0c;结合一些具体的案例进行阐述&#xff0c;本篇博客介绍如何开发一个专属的加密解密windows小应用。 其他相关的博客文章如下&#xff1a; Python开发——工具篇 & Pycharm的相关配置&#xff0c;Python相关操作 &…

OpenAI GPTs 到底是怎么工作的?

▼最近直播超级多&#xff0c;预约保你有收获 今晚直播&#xff1a;《GPTs 构建应用程序案例实现》 —1— GPTs 是如何工作的&#xff1f; OpenAI 官方对 GPTs 的定义是&#xff0c;用户为特定目的创建的 ChatGPT 版本。 GPTs 结合了技能说明、外部知识库和目前可见的 GPT 的任…

【消息中间件】Rabbitmq消息可靠性、持久化机制、各种消费

原文作者&#xff1a;我辈李想 版权声明&#xff1a;文章原创&#xff0c;转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言常见用法1.消息可靠性2.持久化机制3.消息积压批量消费&#xff1a;增加 prefetch 的数量,提高单次连接的消息数并发消费&#xff1a;多部…

最广泛应用的金融风控算法-评分卡

欢迎关注主页个人介绍及相关链接&#xff0c;获取更多算法源码材料 2023数据资源入表白皮书&#xff0c;推荐系统源码下载-CSDN博客 用友BIP数据资产入表解决方案白皮书&#xff0c;推荐系统源码下载-CSDN博客 背景 信用是一切社会金融体系的根本&#xff0c;有了每个人的信…

计算机毕业设计---ssm+mysql+jsp实现的校园二手市场交易平台源码

项目介绍 本系统主要实现的功能有&#xff1a; 前台&#xff1a;&#xff08;1&#xff09;二手物品信息查看、搜索。 &#xff08;2&#xff09;学生注册登录、个人信息修改。 &#xff08;3&#xff09;二手物品信息发布、编辑。 &#xff08;4&#xff09;二手物品评论、回…

axios进行图片上传组件封装

文章目录 前言图片上传接口&#xff08;axios通信)图片上传使用upload上传头像效果展示总结 前言 node项目使用 axios 库进行简单文件上传的模块封装。 图片上传接口&#xff08;axios通信) 新建upload.js文件&#xff0c;定义一个函数&#xff0c;该函数接受一个上传路径和一…