C++临时对象生命周期

引言

朋友问了我一段代码:

const string & foo(const string & a, const string & b)
{return a.empty() ? b : a;
}
int main ()
{auto & s = foo("", "foo"); // auto is const stringcout << s << '\n';return 0;
}

可以思考一下上面的代码能否通过编译?如果可以会输出什么?

UB

对于上面的代码,是可以通过编译的。使用GCC的话输出foo,那么代码似乎没有问题。
其实不然,上述的代码发生了UB(UB是Undefined Behaviour的缩写,意思是未定义行为既具体会发生什么由编译器的实现决定没有官方的要求)。
我们将上面的代码稍作更改:

const string & foo(const string & a, const string & b)
{return a.empty() ? b : a;
}
int main ()
{auto & s = foo("", "foo"); // auto is const stringint a[100] = {0};cout << s << '\n';return 0;
}

在使用GCC的情况下,上面的代码输出了空串。

为什么?临时对象的生命周期

要知道为什么会出现上面的问题,我们需要先了解临时对象的生命周期。

  • 临时对象:临时对象往往是指右值(纯右值和将亡值)。
  • 生命周期:一个对象的生命周期可以理解为从调用构造函数开始到调用析构函数结束的整个过程。

当一个对象的生命周期结束后(调用析构函数后)其不能再被继续使用否则会发生未定义行为。
例如:通过new申请的对象,在delete之后继续进行解引用,此时会发生未定义行为(访问野指针)。
对于上面提到的代码实际上,在输出的时候,"""foo"的生命周期已然结束,所以出现了未定义行为,这是因为在string中用于存放数据的内存已经被回收了(临时对象调用过析构函数),但是s中依然有指向数据的指针(或者引用),当没有数据对对应地址进行写操作的时候,依然能够读出之前的数据,但是增加int a[100] = {0}之前的内存已经被覆盖,因此此时输出空串(但实际上由于是UB此时发生什么都是可以的,这里只是在根据结果解释)。
一个问题:string不是存放在堆上吗,而申请的int a[100]存放在栈上,为什么可以覆盖堆上的内容?

C++string的长度大于某个值时(这个值可能是16),其数据才回被放置在堆上,否则还是存放在栈上。同时string中存放着在栈上的数据,例如字符串长度变量,以及指针存放在栈上(使用new可以使其存放在堆上),通过int a[100] = {0}可以使长度清0和指针变成空指针。

简单说明了上面代码的问题之后,知道了是因为临时对象已经被析构了,导致其发生了未定义行为。那么,临时对象的生命周期究竟如何呢?

  • 对于没有绑定对引用的临时变量其创建完成后,即开始进行析构。例如string("aaa");从该语句的下一行开始,临时变量已经被析构。需要注意的是:string a = string("aaa");实际上会调用移动构造函数,所以该临时变量已经绑定到引用上了,此时不属于未绑定到引用上的临时变量。
  • 对于绑定到引用的临时变量,其生命周期在引用脱离作用域时结束。例如:
    {string &&a = string("xxx");	
    } // string("xxx") is finalized here.
    
  • 特殊地,对于将同一个临时变量绑定到两个不同的引用上,其生命周期以第一个引用为准。例如:
    {string &&a = string("xxx");{string &&b = std::move(a);}// using a here is OK
    } // string("xxx") is finalized here.
    

所以对于引言中的例子,在函数返回之后返回值赋值之前,临时变量已经被析构了。

参考

Lifetime of a temporary cppreference

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

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

相关文章

第二百回 如何获取App自身的信息

文章目录 1. 概念介绍2. 使用方法2.1 ClipOval2.2 ClipRRect 3. 示例代码 我们在上一章回中介绍了AspectRatio Widget相关的内容&#xff0c;本章回中将介绍剪裁类组件(Clip).闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在这里说的剪裁类组件主要是指对…

dockerfile---创建镜像

dockerfile创建镜像&#xff1a;创建自定义镜像。 包扩配置文件的创建&#xff0c;挂载点&#xff0c;对外暴露的端口。设置环境变量。 docker镜像的方式: 1、基于官方源进行创建 根据官方提供的镜像源&#xff0c;创建镜像&#xff0c;然后拉起容器。是一个白板&#xff0c…

初识人工智能,一文读懂强化学习的知识文集(5)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

2023年运营级网赚网盘平台搭建指南(包含源码和教程)

源码介绍 为什么要考虑自己搭建网盘呢&#xff1f;现如今&#xff0c;许多大型网盘平台都对文件添加了各种限制&#xff0c;导致很多文件容易被删除。而且&#xff0c;大部分网盘还会限制下载速度&#xff0c;如果没有开通VIP会员&#xff0c;使用起来非常不便。 本指南提供了…

免费节假日api接口使用教程-聚合数据

免费节假日api接口使用教程-聚合数据 文章目录 &#x1f4d6;访问官网&#x1f330;例子完整代码&#x1f58a;️最后总结 &#x1f4d6;访问官网 聚合数据 官网地址 https://dashboard.juhe.cn/home 点击api 接口文档 &#x1f330;例子 get方式 curl -k -i -d “key您申请…

解决Git提交错误分支

如果 Git 提交到错误的分支&#xff0c;可以通过以下步骤将其转移到正确的分支上&#xff1a; 1.检查当前所在的分支&#xff0c;可以通过 git branch 命令查看。 git branch2.切换到正确的分支&#xff0c;可以通过 git checkout <正确的分支名> 命令进行切换。 git …

vue使用echarts显示中国地图

项目引入echarts以后&#xff0c;在页面创建canvas标签 引入一个公共js文件&#xff08;下面这段代码就是china.js文件&#xff09; (function (root, factory) {if (typeof define function && define.amd) {// AMD. Register as an anonymous module.define([ex…

【EXCEL】折线图添加垂直x轴的竖线|画图

相关链接&#xff1a;excel 添加垂直竖向直线 如何在Excel中添加水平和垂直线&#xff1f; 因为加辅助列有点不习惯&#xff0c;已经有分位数横坐标了&#xff0c;想着试下用散点图的误差线画 效果图&#xff1a; 步骤&#xff1a; s1&#xff1a;随便框选两列数据–>插入(…

大创项目推荐 卷积神经网络手写字符识别 - 深度学习

文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…

深入理解JavaScript异步编程与Promise

异步编程的背景 在Web开发中&#xff0c;异步编程是为了解决JavaScript的单线程执行模型导致的阻塞问题。异步编程允许程序在等待某些操作完成的同时&#xff0c;继续执行其他任务&#xff0c;提高了程序的效率和响应速度。 回调地狱与Promise的诞生 回调地狱是异步编程中一…

Unity中实现ShaderToy卡通火(一)

文章目录 前言一、准备好我们的后处理基础脚本1、C#&#xff1a;2、Shader&#xff1a; 二、开始逐语句对ShaderToy进行转化1、首先&#xff0c;找到我们的主函数 mainImage2、其余的方法全部都是在 mainImage 函数中调用的方法3、替换后的代码(已经没报错了&#xff0c;都是效…

智能优化算法应用:基于正余弦算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于正余弦算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于正余弦算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.正余弦算法4.实验参数设定5.算法结果6.参考文…

基于单个参数线性回归的机器学习代码

本文为学习吴恩达版本机器学习教程的代码整理&#xff0c;使用的数据集为https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes/blob/f2757f85b99a2b800f4c2e3e9ea967d9e17dfbd8/code/ex1-linear%20regression/ex1data1.txt 将数据集和py代码放到同一目录中&#xff0c;使…

2023最新八股文前端面试题

第一章 Css 1.说一下CSS的盒模型。 在HTML页面中的所有元素都可以看成是一个盒子盒子的组成:内容content、内边距padding、边框border、外边距margin盒模型的类型: 标准盒模型 margin border padding content IE盒模型 margin content(border padding) 控制盒模型的模式…

淘宝api接口测试方式(item_get-获得淘宝商品详情)

注册淘宝开放平台账号&#xff1a;首先&#xff0c;你需要在淘宝开放平台上注册一个账号&#xff0c;并创建一个应用。获取App Key和Secret Key&#xff1a;在创建应用后&#xff0c;你会获得App Key和Secret Key&#xff0c;这些凭证将用于调用API。了解淘宝商品详情接口&…

【开源】基于Vue+SpringBoot的免税店商城管理系统

文末获取源码&#xff0c;项目编号&#xff1a; S 069 。 \color{red}{文末获取源码&#xff0c;项目编号&#xff1a;S069。} 文末获取源码&#xff0c;项目编号&#xff1a;S069。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.2 研究方法 三、系统…

什么是图片懒加载(image lazy loading)?它的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

如何使用vue开发vscode插件

以下是一个简单的示例&#xff0c;演示如何使用Vue和VSCode的Webview API来开发一个简单的VSCode插件&#xff1a; 创建一个VSCode插件项目 首先&#xff0c;你需要创建一个VSCode插件项目。你可以使用VSCode的插件生成器来快速创建一个基本的项目结构。从VSCode的命令面板中运…

【Flutter】graphic图表实现tooltip一段时间后自动隐藏

概述 graphic图表中提供了自定义tooltip的事件&#xff0c;可通过selections中on和clear配置手势选项和可识别设备&#xff0c;默认情况下tooltip需要双击隐藏&#xff0c;但这并不符合我们的需求。通过调研发现&#xff0c;若想实现tooltip隔几秒后隐藏&#xff0c;可通过Str…

3DMax物理画笔物体填充放置绘制画笔插件安装使用方法

3DMax物理画笔物体填充放置绘制画笔插件&#xff0c;允许您使用笔刷以非常自然的方式用物品快速填充场景&#xff0c;并使用刚体模拟自动放置它们。 无论你是从事建筑、游戏电影还是商业。。。等等&#xff0c;你经常需要用一些物品为你的场景添加细节。手工放置它们是乏味的&…