[c++]实例观察返回值优化

1 返回值优化现象 RVO

如下代码,在 MakeObj() 中创建了一个局部对象 obj,并将 obj 返回。 Test() 函数调用了 MakeObj(),并将 MakeObj() 的返回值赋值给了 obj。

按我们的预期,MakeObj() 是值返回,在 main() 调用 Test() 的过程中,应该发生了两次构造和两次析构。

第一次构造:默认构造,在 MakeObj() 声明局部变量的时候。

第二次构造:拷贝构造,在 MakeObj() 返回的时候,将返回值赋值给 Test() 中的局部变量 obj 时

第一次析构:在函数 Test() 中,MakeObj() 返回值赋值给 Test() 中的 obj 完成时, MakeObj() 中的局部变量析构

第二次析构:在函数 Test() 返回时,Test() 函数中的 obj 析构

#include <iostream>class Obj {
public:Obj(int i) {i_ = i;std::cout << "Obj(), i: " << i_ << ", this: " << this << std::endl;}Obj(const Obj &obj) {i_ = obj.i_;std::cout << "copy constructor, i: " << i_ << ", this: " << this << std::endl;}~Obj() {std::cout << "~Obj(), i: " << i_ << ", this: " << this << std::endl;}int i_;};Obj MakeObj() {int a = 10;Obj obj(1);int b = 10;printf("1, &obj = %p, &a = %p, &b = %p, sizeof(obj) = %d\n", &obj, &a, &b, sizeof(obj));return obj;
}void Test() {printf("before make obj\n");int a = 100;Obj obj = MakeObj();int b = 100;printf("2, &obj = %p, &a = %p, &b = %p\n", &obj, &a, &b);printf("after make obj\n");
}int main() {Test();printf("before main return\n");return 0;
}

编译之后运行,现象与我们预期的并不是一致的。如下图所示,只发生了一次构造和一次析构。

并且在 MakeObj() 和 Test() 中均把 obj 的地址打印出来了,两个对象的地址是一样的。

2 禁用返回值优化:-fno-elide-constructors

g++ 编译的时候,默认开启了返回值优化,如果想要禁用返回值优化,那么在编译时需要带上标志 -fno-elide-constructors。

如下图所示,禁用返回值优化之后,运行过程与我们预期的是一致的。

 

3 局部变量在函数返回的时候没有销毁吗

从上边的实验可以看出,默认情况下,编译器开启了返回值优化。但是从常识来看,函数返回的时候,局部变量(栈空间)要释放,对象会销毁。

那么开启返回值优化的时候,函数返时,难道局部对象没有销毁 ? 

开启返回值优化的时候,并没有违反栈销毁的规律。

从上边的打印结果可以看出来,在函数 MakeObj() 以及 Test() 函数中,局部变量 obj 前后分别定义了局部变量 a 和 b,把 a 和 b 的地址也打印出来了。

局部变量都是保存在栈上,一个函数中的多个局部变量的地址应该是相邻的才对。但是看打印结果,obj 的地址和 MakeObj() 中的 a 和 b 的地址并不是相邻的,而是和 Test() 中的 a 和 b 是相邻的。这就是编译器起的作用,编译器判断变量的生命周期,然后决定将局部变量放在哪个位置。

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

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

相关文章

Go 使用环境变量

作为软件开发人员&#xff0c;我们深知在项目中管理配置变量的重要性。在本篇文章中&#xff0c;我将介绍在 Golang 中处理环境变量的强大工具 github.com/joho/godotenv 包。利用这个包&#xff0c;你可以简化处理 .env 文件的过程&#xff0c;确保更顺畅的开发体验。 步骤 1…

2.1tarjian算法求解双连通分量

P2860 [USACO06JAN] Redundant Paths G 就是说通过加边&#xff0c;使得图中的每一点都不是割点&#xff0c;就是让连通图中没有桥&#xff0c;没有割点 并非是桥的数量-1 边双连通分量即一个无向图中&#xff0c;去掉一条边后仍互相连通的极大子图。&#xff08;单独的一个…

基于编译器的静态代码分析与软件开发效率、质量和性能

基于编译器的静态代码分析与软件开发效率、质量和性能 本文节选自《基础软件之路&#xff1a;企业级实践及开源之路》一书&#xff0c;该书集结了中国几乎所有主流基础软件企业的实践案例&#xff0c;由 28 位知名专家共同编写&#xff0c;系统剖析了基础软件发展趋势、四大基…

袁庭新ES系列10节 | 使⽤kibana对⽂档操作

前言 在前面的小节中&#xff0c;我们已经给大家介绍了Elasticsearch中文档的相关概念&#xff0c;想必有些同学都已经忘记了&#xff0c;那我们一块儿再来回顾下&#xff0c;文档即索引库中某个类型下的数据&#xff0c;会根据规则创建索引&#xff0c;将来用来搜索。可以类比…

Nacos、Eureka、Zookeeper注册中心的区别

Nacos、Eureka和Zookeeper都是常用的注册中心&#xff0c;它们在功能和实现方式上存在一些不同。 Nacos除了作为注册中心外&#xff0c;还提供了配置管理、服务发现和事件通知等功能。Nacos默认情况下采用AP架构保证服务可用性&#xff0c;CP架构底层采用Raft协议保证数据的一…

HTML+CSS:动态搜索框

效果演示 这段代码实现了一个简单的搜索栏效果。页面背景为从天蓝色到深蓝色的渐变色&#xff0c;搜索栏包括一个圆形背景的搜索图标和一个输入框。当用户点击搜索图标时&#xff0c;输入框会从搜索图标的位置滑出&#xff0c;显示一个输入框和一个清除按钮。用户可以在输入框中…

Unity(第三部)新手绘制地形

1、创建地形 游戏对象3d对象地形 2、功能 1、 红框内按键为创建相邻地形、点击后相近地形会呈现高亮框、点击高亮区域可以快速创建地形 每块地形面积是1km*1km 2、第二个按钮是修改地形 下面的选择是修改类型 选项含义描述Raise or Lower Terrain升高或降低地形单击左键可…

chat GPT第三讲

ChatGPT的能力边界在哪&#xff1f; ChatGPT在今天被热炒&#xff0c;主要的原因不是因为它能和人聊天&#xff0c;或者能帮助人做作业。其实做作业这件事它做得并不好&#xff0c;虽然有些中学和大学的问题它能够解决&#xff0c;但是对于绝大部分问题&#xff0c;它给出的答案…

pikachu靶场-File Inclusion

介绍&#xff1a; File Inclusion(文件包含漏洞)概述 文件包含&#xff0c;是一个功能。在各种开发语言中都提供了内置的文件包含函数&#xff0c;其可以使开发人员在一个代码文件中直接包含&#xff08;引入&#xff09;另外一个代码文件。 比如 在PHP中&#xff0c;提供了&…

5G网络(接入网+承载网+核心网)

5G网络&#xff08;接入网承载网核心网&#xff09; 一、5G网络全网架构图 这张图分为左右两部分&#xff0c;右边为无线侧网络架构&#xff0c;左边为固定侧网络架构。 无线侧&#xff1a;手机或者集团客户通过基站接入到无线接入网&#xff0c;在接入网侧可以通过RTN或者IP…

uniapp中在app中清除缓存功能

1.计算缓存大小 //计算缓存大小getStorageSize() {let that this;let fileSizeString "";let isFlag arrIndex(this.menuList, key, my-ql)plus.cache.calculate(function(size) {let sizeCache parseInt(size);if (sizeCache 0) {fileSizeString "0B&q…

实现获取 两个时间之间的工作日工作时长(mysql)

实现功能&#xff1a; 计算两个时间之间的时长&#xff1a; 要求&#xff1a; 1. 计算工作日 2. 只计算 8:00-20:00 之间的时间&#xff0c;其他时间不计入时长 计算逻辑&#xff1a; 1. 首先维护一个表 ,该表存储假期信息 CREATE TABLE holiday (id int(10) NOT NULL AUTO_INC…

如何在Linux Ubuntu系统使用Docker快速部署MongoDB并公网访问

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主要介绍如何在Linux Ubuntu系统使用Docker快速部署Mon…

不要再使用lock来锁定,这种方式让你更省事

设置读写锁为写入模式独占资源&#xff0c;其他写入请求需要等待本次写入结束之后才能继续写入注意&#xff1a;长时间持有读线程锁或写线程锁会使其他线程发生饥饿 (starve)。 为了得到最好的性能&#xff0c;需要考虑重新构造应用程序以将写访问的持续时间减少到最小。从性能…

Ubuntu 21.04 设置ai服务开机自启动的两种方法

Ubuntu 21.04 设置ai服务开机自启动的两种方法 方法1 /lib/systemd/system方法2 /etc/systemd/system 方法1 /lib/systemd/system 1.1.修改/lib/systemd/system/rc-local.service&#xff0c;如果没有需要新建&#xff0c;添加[Install]的内容&#xff0c;文件内容为 [Unit] …

互联网加竞赛 机器视觉 opencv 深度学习 驾驶人脸疲劳检测系统 -python

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#x…

uniapp使用sqlite

1、判断数据库是否打开 isOpen() {let open plus.sqlite.isOpenDatabase({name: this.dbName,path: this.dbPath})return open;} 2、创建数据库(有就打开) openSqlite() {return new Promise((resolve, reject) > {plus.sqlite.openDatabase({name: this.dbName,path: th…

【Spring连载】使用Spring Data访问 MongoDB(七)----会话和事务

【Spring连载】使用Spring Data访问 MongoDB&#xff08;七&#xff09;----Sessions & Transactions 一级目录二级目录三级目录 一级目录 二级目录 三级目录

8.qt5使用opencv的库函数打开图片

1.配置opencv动态库的环境变量 2.在创建的qt工程中加入如下opencv代码&#xff0c;具体代码如下&#xff1a; 使用opencv库函数显示图片

C/C++ BM17 二分查找-I

文章目录 前言题目解决方案一1.1 思路阐述1.2 源码 总结 前言 一篇简单的二分查找的运用 题目 描述 请实现无重复数字的升序数组的二分查找 给定一个 元素升序的、无重复数字的整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如…