【C++】拷贝对象时,编译器的偷偷优化

你知道吗?对于连续的”构造+拷贝构造“,编译器其实是会默默做出优化的。👻

如果你不知道这个知识点的话,那下面这道笔试题就要失分了😵。

本篇分享一个关于编译器优化的小知识,看完本篇,你就能知道程序里的 构造函数、拷贝构造函数 究竟被调了几次~

题目引入

某笔试题:下面的程序经历了几次构造?几次拷贝构造?

答案为:

1次构造,4次拷贝

对此题的分析在本篇末尾。如果你对这道题尚有存疑,那相信看完本篇,你的疑惑将会烟消云散~👻

传值传参 的优化

我们知道,传值传参会产生拷贝,因为这样能保证 函数内部对参数的操作 不会影响到原始变量的值。

➡️先看一个没做优化的例子:

class W
{
public://构造函数W(int w) :_w(w){cout << "W()" << endl;}//拷贝构造函数W(const W& w) :_w(w._w){cout << "W(const W& w)" << endl;}//析构函数~W(){cout << "~W()" << endl;}
private:int _w;
};
void func(const W w) {}
int main()
{W w1=1;  //构造func(w1);   //拷贝构造:把w1的值拷贝一份,传到形参return 0;
}

调用情况我们打印出来:

可见这种情况下:

W w1=1;
func(w1);

是老老实实调用构造+拷贝构造的,并没有做出优化。

➡️再看一个做了优化的例子:

class W
{
public://构造函数W(int w) :_w(w){cout << "W()" << endl;}//拷贝构造函数W(const W& w) :_w(w._w){cout << "W(const W& w)" << endl;}//析构函数~W(){cout << "~W()" << endl;}
private:int _w;
};
void func(const W w) {}
int main()
{func(W(1));  //一个表达式步骤中,有连续的”构造+拷贝构造“return 0;
}

结果:

我们发现:这次没调拷贝构造了!看来编译器做了优化。

原本,这个表达式的执行顺序是:W(1)先构造出一个W,这个W再拷贝构造,传递给形参,参与表达式func()。

func(W(1));

而编译器做出了优化:

将连续的 构造+拷贝构造 优化成一步构造。

动图可以更直观地看出来:

传匿名对象 的优化

我们学过的匿名对象,也是可以传参过去的,它的优化和刚刚讲的传值传参的优化 道理是一样的。

class W
{
public:W() {cout << "W()" << endl;}W(const W& w) {cout << "W(const W& w)" << endl;}~W(){cout << "~W()" << endl;}
};
void f1(W w) {
​
}
int main()
{f1(W());   //先构造一个匿名对象,然后作为参数 传值传参过去return 0;
}

结果:

依然没调用拷贝构造。

看看程序怎么运行的:

还是刚刚讲的,这是因为编译器的优化,将 构造+拷贝构造 直接优化成了 一步构造。

结论:一个连续的表达式步骤中,连续构造一般都会被优化。

传值返回

可以优化的情况:

class W
{
public://构造函数W(int w=0) :_w(w){cout << "W()" << endl;}//拷贝构造函数W(const W& w) :_w(w._w){cout << "W(const W& w)" << endl;}//析构函数~W(){cout << "~W()" << endl;}
private:int _w;
};
​
W func() {W ret;  //1次构造return ret;  //1次拷贝构造:将ret的值通过拷贝构造返回
}
​
int main()
{W w1=func();  //W w1=……仍是一次拷贝构造。所以按理说是“1构造+2拷贝构造”return 0;
}

然而实际上只进行了“1构造+1拷贝构造”:

为什么拷贝构造从2次变成了1次?

原来,这也是编译器的优化,它会将两个拷贝构造,优化成一个。

这里用图说明一下:

不能优化的情况

上面这种情况和下面的这种要区分,下面这种是不能优化的:

class W
{
public://构造函数W(int w=0) :_w(w){cout << "W()" << endl;}//拷贝构造函数W(const W& w) :_w(w._w){cout << "W(const W& w)" << endl;}//赋值运算符W& operator=(const W& w) {cout << "W& operator=(const W& w)" << endl;if (this != &w) {_w = w._w;}return *this;}//析构函数~W(){cout << "~W()" << endl;}
private:int _w;
};
W func() {W ret;return ret;
}
​
int main()
{W w1; w1 = func();  //赋值接收对象return 0;
}

这种是分4步进行的:

可见,赋值接收对象 不如 拷贝构造的方式接收。后者可以被优化。

总结

1.连续的 构造和拷贝构造 会被优化成 直接调用构造。(分步的就无法优化了)

2.产生的临时变量往往会被优化掉。

题目的解析

我们现在回过头看看一开始那道题:

首先,W x;是1次构造。

然后,f(x)会把x的值拷贝给u,是1次拷贝构造。

在函数f(W u)里,v的实例化是1次拷贝构造.

w究竟是拷贝构造还是赋值的呢?因为w原先不存在,所以不是赋值,是1次拷贝构造。

return w;(这里最易错) 原本是要拷贝产生临时变量,再用临时变量拷贝构造出y的。但经过编译器的优化,升级成一步拷贝构造。

所以,一共1构造+4拷贝构造。

把这题升级一下:

几次构造?几次拷贝构造?

和上题同理,只不过这次return w将连续的三步优化成一步。

答案:1次构造 7次拷贝构造

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

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

相关文章

面试题 ⑤

1、TCP与UDP的区别 UDPTCP是否连接无连接&#xff0c;即刻传输面向连接&#xff0c;三次握手是否可靠不可靠传输&#xff0c;网络波动拥堵也不会减缓传输可靠传输&#xff0c;使用流量控制和拥塞控制连接对象个数支持一对一&#xff0c;一对多&#xff0c;多对一和多对多交互通…

【kubernetes】Argo Rollouts -- k8s下的自动化蓝绿部署

蓝绿(Blue-Green)部署简介 在现代软件开发和交付中,确保应用程序的平稳更新和发布对于用户体验和业务连续性至关重要。蓝绿部署是一种备受推崇的部署策略,它允许开发团队在不影响用户的情况下,将新版本的应用程序引入生产环境。 蓝绿部署的核心思想在于维护两个独立的环…

【算法与数据结构】700、LeetCode二叉搜索树中的搜索

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;二叉搜索树的性质&#xff1a;左节点键值 < 中间节点键值 < 右节点键值。那么我们根据此性质&am…

文件上传漏洞-upload靶场5-12关

文件上传漏洞-upload靶场5-12关通关笔记&#xff08;windows环境漏洞&#xff09; 简介 ​ 在前两篇文章中&#xff0c;已经说了分析上传漏的思路&#xff0c;在本篇文章中&#xff0c;将带领大家熟悉winodws系统存在的一些上传漏洞。 upload 第五关 &#xff08;大小写绕过…

微服务主流框架概览

微服务主流框架概览 目录概述需求&#xff1a; 设计思路实现思路分析1.HSF2.Dubbo 3.Spring Cloud5.gRPC Service mesh 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a be…

无涯教程-Android - List fragments函数

框架的ListFragment的静态库支持版本&#xff0c;用于编写在Android 3.0之前的平台上运行的应用程序&#xff0c;在Android 3.0或更高版本上运行时,仍使用此实现。 List fragment 的基本实现是用于创建fragment中的项目列表 List in Fragments 示例 本示例将向您说明如何基于…

地图投影——1 投影目录

地图投影示例说明亚当斯方形 II该投影以方形显示世界。该投影为等角投影&#xff0c;但方形的四个角除外。埃托夫该折衷改进的方位投影采用椭圆的形式。该投影主要用于世界地图。阿尔伯斯该等积圆锥投影最适合用于中纬度东西方向分布的大陆板块。方位自适应圆柱该折衷的地图投影…

【Yellowbrick】特征可视化分析

Yellowbrick特征可视化分析 ⭐Yellowbrick⭐特征分析可视化⭐Rank1D⭐Rank2D ⭐Yellowbrick Yellowbrick是一个用于可视化机器学习模型和评估性能的Python库。它提供了一系列高级可视化工具&#xff0c;帮助数据科学家和机器学习从业者更好地理解、调试和优化他们的模型。 它在…

JVM性能优化 —— 类加载器,手动实现类的热加载

一、类加载的机制的层次结构 每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑&#xff0c;这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件&#xff0c;”.class”文件中保存着Java代码经转换后的虚拟机指令&#xff0c;当需要使用某个类时&#…

react利用wangEditor写评论和@功能

先引入wangeditor写评论功能 import React, { useEffect, useState, useRef, forwardRef, useImperativeHandle } from react; import wangeditor/editor/dist/css/style.css; import { Editor, Toolbar } from wangeditor/editor-for-react; import { Button, Card, Col, For…

文件包含漏洞利用的几种方法

文章目录 安装环境启动环境漏洞花式利用蚁剑连接图片马读取敏感文件&#xff08;hosts&#xff09;读取该网站的php源码 代码审计 安装环境 安装phpstudy&#xff0c;下载MetInfo 5.0.4版本软件&#xff0c;复制到phpstudy目录下的www目录中。 打开phpstudy&#xff0c;访问浏…

Typora for Mac(Markdown文本编辑器)

Typora是一款简洁、直观的跨平台Markdown编辑器软件。它提供了一个非常直观和简单的界面&#xff0c;让用户可以更轻松地编写和编辑Markdown语言的文档。 Typora具有实时预览功能&#xff0c;这意味着你可以在编辑Markdown文档的同时立即看到最终的效果。它允许用户快速切换编辑…