C/C++陷阱——临时变量的产生和特性

C/C++陷阱——临时变量的产生和特性

在学习C++常引用时,有这样一段代码引起了我的注意:

int a = 1;
double& b = a;

当我编译这段代码时,竟然报错了:

在这里插入图片描述

按理来说,初始化引用时不能涉及权限的放大(如用const int初始化int&),但是这里只是权限的平移,为什么会错误呢?

我们可以看到报错信息里有这样一句话:非常量限定,这指的又是什么呢?

这就是本次要讨论的重点——临时变量的产生和特性

在C和C++中,临时变量通常指的是临时创建并存储数据的变量,它们在表达式求值或函数调用中起到临时存储值的作用。这些临时变量通常是由编译器自动生成的,无需程序员显式声明或管理

临时变量的产生

临时变量主要在下面这两种情况下产生:

  1. 类型转换

当需要将一个数据类型转换为另一个数据类型时,通常会生成临时变量来保存转换后的值

例如:

int a = 10;
double b = a;

我们都知道,将整型变量a赋值给双精度浮点型变量b时,涉及到了隐式类型转换,但我们可能大多数都忽略了这个过程中就产生了一个临时变量来存储转换后的值,最后变量b接收的就是这个临时变量。因为只有这样,我们才能在类型转换的过程中确保变量a的数据是完整的、合规的、安全的。

又例如:

int a = 1;
int* pt = (int*)a;

我们总不能说,将整型变量a强制转换为整型指针后,整型变量a就变成指针了吧。

  1. 函数调用

当一个函数返回一个值时,通常会生成临时变量来存储函数的返回结果。这个临时变量可以被赋给其他变量或用于进一步的操作。

int Add(int a, int b)
{int sum = a + b;return sum;
}int main()
{int ret = Add(1, 2);return 0;
}

Add函数就是一个简单的两数相加的函数。那么小伙伴觉得这个函数的返回值是什么?是变量sum吗?当然不是,应该清楚局部变量出了其所在函数的作用域后就会被销毁,因此当Add函数被调用完后,sum所代表的值就是一个随机数了。因此实际上,编译器一般都会生成一个临时变量来存储函数返回的结果,最后ret接受的也是这个临时变量。

除了上面两种情况外,还有其他的一些情况也会有临时变量的产生,大家了解即可:

  1. 表达式求值:当需要计算一个表达式,特别是包含多个操作数和操作符的复杂表达式时,编程语言通常会生成临时变量来保存中间结果。
  2. 中间计算:在执行复杂计算时,可以使用临时变量来存储中间计算结果,以避免重复计算相同的值。
  3. 循环迭代:在循环结构中,迭代计数器通常被视为临时变量,因为它们在每次迭代中都会被更新。
  4. 条件语句:在条件语句中,如果需要根据条件执行不同的操作,临时变量可能会用于存储条件的结果或中间值。
  5. 数组和容器操作:在对数组、向量、列表等数据结构进行操作时,可能会生成临时变量来存储临时元素或中间结果。
  6. 错误处理:在处理异常或错误时,临时变量可以用于存储错误信息或状态。

临时变量的常性

临时变量有一个很重要的特性:常量性

这一个特性确保了临时变量是不可以被修改,这其中也就包括了权限不能被放大

例如:

int Add(int a, int b)
{int sum = a + b;return sum;
}int main()
{Add(1, 2)++;return 0;
}

就会报错:

这里解释一下左值和右值的概念:

  1. 左值(L-value):左值是可以出现在赋值操作符(例如=)的一侧的表达式,表示一个可以被赋值的内存位置通常是一个变量。左值表示一个标识符或一个引用,它指向内存中的某个位置。例如,如果你有一个变量x,那么x就是一个左值,因为你可以将一个值赋给它,如x = 10。
  2. 右值(R-value):右值是一个表达式的结果值,它可以出现在赋值操作符的右侧。右值通常是计算的结果,它可以是常数、临时变量或函数的返回值。例如,如果你有一个表达式x + y,它的结果是一个右值,因为它代表一个值,但你不能将一个值赋给它。

报错信息显示,函数的返回值不是一个左值,也就是说返回的临时变量是不可被修改的。这也从侧面反映了临时变量的常性。

除此之外,临时变量还有其他一些特性,大家仅作了解即可:

  1. 短暂寿命:临时变量通常在其创建点的作用域内存在,一旦超出该作用域,它们就会被销毁。这使它们成为一种短暂的存储设备。
  2. 匿名:通常,临时变量没有显式的名称,因为它们是在表达式求值或函数调用期间自动创建的。它们只是在内部存储中的值。
  3. 用于中间计算:临时变量通常用于存储中间计算结果或值的转换。它们帮助管理复杂的表达式,确保正确的计算顺序。
  4. 可被编译器优化:现代编译器通常会进行优化,以最小化临时变量的使用,以提高性能。它们可以消除不必要的临时变量,以减少内存开销。
  5. 值语义:临时变量通常采用值语义,这意味着它们存储的是具体的值,而不是引用或指向其他变量。这有助于避免共享状态和副作用。
  6. 用于函数返回:在函数返回值的情况下,临时变量通常用于存储函数的结果,以便将其传递给调用方。
  7. 隐式创建和销毁:编程语言和编译器通常会自动创建和销毁临时变量,程序员无需显式管理它们的生命周期。
  8. 类型与原始值相关:临时变量的类型通常与它们所包含的值的类型相关,以确保类型的一致性。

总结

通过对临时变量的了解,我们就可以解释最开始提到的问题了:

int a = 1;
double& b = a;

当用整形变量a初始化浮点型引用b时,涉及到了隐式类型转换,那么中间就会产生一个double临时变量来临时存储a的值,但由于临时变量具有常性,其权限不能被放大,因此double& b = a;这句就是错误的。我们应该改为**const double& b = a;确保权限不变**。


本篇完。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka生产者使用案例

本文代码链接:https://download.csdn.net/download/shangjg03/88422633 1.生产者发送消息的过程 首先介绍一下 Kafka 生产者发送消息的过程: 1)Kafka 会将发送消息包装为 ProducerRecord 对象, ProducerRecord 对象包含了目标主题和要发送的…

如何正确维护实验室超声波清洗器?

实验室一直被视为一个严谨而严肃的场所,实验应遵循一定的步骤,使用的设备也经历了详细的选择,如实验室超声波清洗机,其特点远强于一般类型的清洗机。专门负责采购的实验室人员一般对优质服务的实验室超声波清洗机印象深刻&#xf…

计算机毕业设计 无人智慧超市管理系统的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…

MySQL学习(二)——MySQL内置函数

文章目录 1. 函数1.1 字符串函数1.2 数值函数1.3 日期函数1.4 流程函数 2. 约束2.1 概述2.2 外键约束2.2.1 外键使用2.2.2 删除/更新行为 1. 函数 和其他编程语言一样,MySQL也有函数的定义。函数 是指一段可以直接被另一段程序调用的程序或代码。 也就意味着&#…

竞赛 深度学习OCR中文识别 - opencv python

文章目录 0 前言1 课题背景2 实现效果3 文本区域检测网络-CTPN4 文本识别网络-CRNN5 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **基于深度学习OCR中文识别系统 ** 该项目较为新颖,适合作为竞赛课题方向,…

xcode打包macos报错:FlutterInputs.xcfilelist 和 FlutterOutputs.xcfilelist

xcode 打包macos的时候,报错如下: Unable to load contents of the file list: ‘macos/ephemeral/FlutterInputs.xcfilelist’ ‘macos/ephemeral/FlutterOutputs.xcfilelist’ 解决方案: 我的项目macos下没有找到FlutterInputs.xcfilelis…

k8s-10 cni 网络

k8s通过CNI接口接入其他网络插件来实现网络通讯。目前比较流行的插件有flannel,calico等。 CNI插件存放位置: # cat /etc/cni/net.d/10-flannel.conflist 插件使用的解决方案如下: 虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。多路复用: Mac…

零经验想跳槽转行网络安全,需要准备什么?

最近在后台看到很多私信都是有关转行网络安全的问题,目前咨询最多的都是:觉得现在的工作没有发展空间,替代性强,工资低,想跳槽转行网络安全。其中,他们主要关心的是:没有经验怎么学习&#xff1…

2022最新版-李宏毅机器学习深度学习课程-P14 批次(batch)与动量(momentum)

一、batch 回顾epoch、shuffle batch size大还是小?都有好处 大batchsize的好处 由于GPU有并行计算的能力,左边并不一定用时更长 反而是,batch size小的时候,要跑完一个epoch所用的update时间更长,所以时间方面的比较…

java 两个list比较,删除相同的元素

概述 在Java开发中,经常需要比较两个List并删除相同的元素。本文将介绍整个流程,并提供相应的代码示例,帮助新手开发者完成这个任务。 流程 下面是比较两个List并删除相同元素的流程: 代码示例 创建两个List 我们首先需要创建两…

[开源]企业级流程中心,基于flowable和bpmn.js封装的流程引擎

一、开源项目简介 企业级流程中心(基于flowable和bpmn.js封装的流程引擎,采用Springboot,Mybatis-plus, Ehcache, sa-token 等框架技术,前端采用Vue3&Antd,Vben)。 二、开源协议 使用Apache-2.0开源协议 三、界…

docker 复习

文章目录 docker 安装配置镜像加速器拉取镜像的仓库: docker 部署Mysql 镜像命令的详细解释docker 相关命令总结 docker 安装 查看是否安装的镜像已经在系统中存在: docker images (存在2,不存在 3) 卸载旧版本 yum r…

技术分享:深入浅出讲解GLSB是什么?

在互联网早期,由于网络不是很发达,流量也相对比较小,单体架构已经能足够满足需求。但伴随着互联网越来越,网站的流量请求甚至能达到上千亿。为了实现高可用,需要用到多台机器来提升处理流量的能力。在这种环境下&#…

C++项目实战——基于多设计模式下的同步异步日志系统-⑫-日志宏全局接口设计(代理模式)

文章目录 专栏导读日志宏&全局接口设计全局接口测试项目目录结构整理示例代码拓展示例代码 专栏导读 🌸作者简介:花想云 ,在读本科生一枚,C/C领域新星创作者,新星计划导师,阿里云专家博主,C…

DevExpress Reporting中文教程 - 如何在macOS等系统中生成导出报表文档

DevExpress Reporting是.NET Framework下功能完善的报表平台,它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集,包括数据透视表、图表,因此您可以构建无与伦比、信息清晰的报表。 在本文中,我们将讨论如何在.NET MA…

如何制作有专业水准的的电子杂志:专家教你秘籍

​随着数字化时代的到来,电子杂志作为一种新型的传媒形式,越来越受到人们的关注和喜爱。但是,如何制作一份具有专业水准的电子杂志呢? 今天,给大家分享一款在线就能制作的电子杂志------FLBOOK,让你轻松打造…

宝塔面板部署express以及MySql项目

第一次在宝塔面板上部署express和MySql项目,部署过程一直跑不通接口,特此记录一下。 在部署的时候,建议第一步把数据库MySql给跑通,中间好多原因是由于数据库的原因给引起的。 一.连接数据库 (1)在宝塔面…

CSS变量 var()的用法

写在前面 这里介绍一下开发中常用的css变量var(),它可以实现样式的动态设置,使用方法主要分为全局使用和局部使用两种。 如何定义CSS变量var() 在CSS文件中,变量需要使用 – 作为前缀来定义,后面跟上变量名和值,如&a…

从0开始学go第八天

gin获取URL路径参数 package main//获取path(URL)参数 import ("net/http""github.com/gin-gonic/gin" )func main() {r : gin.Default()r.GET("/:name/:age", func(c *gin.Context) {//获取路径参数name : c.Param(&quo…

Python 连接数据库添加字段

任务需求: 数据库hospital集合所有数据添加一个八位数的编码 import pymongo# 连接数据customer(库)hospital(集合) client pymongo.MongoClient(host127.0.0.1) db client.customer collection db.hospitalhospit…