当前位置: 首页 > news >正文

编译器对连续构造的优化

一:优化的规则

在一行代码中连续进行:构造+构造/构造+拷贝构造/拷贝构造+拷贝构造   都会合二为一

如下:

a:构造+构造->构造

b:构造+拷贝构造->构造

c:拷贝构造+拷贝构造->拷贝构造

注意:不同的编译器优化的效果可能会不同(博主是在 VS19 下的 Debug 版本下进行演示)

二: 优化展示

以下是一个用于测试的类A,其有构造函数,拷贝函数,赋值重载函数,构析函数,进入每个函数都会打印调用了一次 xx函数 的字眼,这样更能显式的看出优化

class A
{
public://构造函数A(int a = 0):_a(a){cout << "A(int a)调用一次构造" << endl;}//拷贝函数A(const A& aa):_a(aa._a){cout << "A(const A& aa)调用一次拷贝" << endl;}//赋值重载函数A& operator=(const A& aa){cout << "A& operator=(const A& aa)调用一次赋值" << endl;if (this != &aa){_a = aa._a;}return *this;}//构析函数~A(){cout << "~A()调用一次构析" << endl;}
private:int _a;
};

①:在一行代码的构造+拷贝

情况1:
int main()
{A aa1 = 1;return 0;
}

解释:

a:aa1是A类实例化的对象,而1是整形,这叫作类型转换

b:类型转换 的规则如下:

所有的类型转换都是不会影响到本身的,图中来说就是不会影响到1,并不是1真的变成了一个对象,而是1先作为参数进行了匿名构造,构造出一个中间的对象(且中间变量都是具有常属性,即不能被更改),然后这个中间对象再去进行拷贝构造出了aa1(用一个已存在的对象去初始化一个未存在的对象,调用拷贝构造)

c:所以这里在同一行代码中进行构造+拷贝构造,所以优化成了:

结果:

解释:正如前文的规则,优化成了只调用了一次构造(构析是aa1出了main函数调用了)

Q:为什么不是直接进行拷贝构造呢?为什么要生成中间变量?不会压根没有中间变量的生成吧?

A:如果没有中间变量的生成,那从1到aa1就应该是变量到变量,那为何以下这样写不行呢?

A& aa1 = 1;

这样不是只是对生成的aa1进行了引用而已吗?为什么就不行了呢。报错如下:

正确写法:

const A& aa1 = 1;

解释:const修饰的是常变量,具有不可变的性质,只能这样写也说明了,的确是有中间变量的产生,其进行拷贝构造给了aa1,因为中间变量是有常属性的,我们的aa1被常属性的对象初始化,所以我们的aa1的引用才需要const修饰

情况2:
void func(A aa1)
{}int main()
{//匿名构造仅是构造(不是类型转换,谈何构造加拷贝),然后再拷贝传参func(A(2));return 0;
}

解释:

a:func(A(2)),中的A(2)是一次匿名构造,调用了一次构造函数

b: A(2)构造出来的对象传入func函数,调用了一次拷贝函数

c:所以是一次构造 + 拷贝,但是是在同一行上连续进行的,所以优化成了:

情况3:
void func(A aa1)
{}
//构造+拷贝构造->构造 
int main()
{//3 到 aa1 是隐示类型转换 先构造 在拷贝func(3);return 0;
}

解释:

a:3直接作为参数给func函数的aa1接收,这是类型转换,如情况1中的意义,先进行构造,再进行拷贝,所以 应该是 在一行上进行 构造 + 拷贝,优化成了:

②:不在一行的的构造 + 拷贝

void func(A aa)
{}int main()
{A aa1(1);func(aa1);return 0;
}

解释:

a:A aa1(1),是一次构造函数的调用

b:func(aa1),将aa1传给了func函数,是一次拷贝函数的调用

c:所以这是  构造 + 拷贝函数 ,但是不会被优化,因为其不是在一行上连续进行的

结果:

两次构析是aa 和  aa1 离开自己的作用域调用的

③:在一行的的拷贝+ 拷贝

A func()
{A aa;return aa;
}int main()
{A aa1 = func();return 0;
}

解释:

a:func函数中 aa是一次构造,return aa 是一次拷贝 ,A aa1 中的 aa1 还未存在,此时去接受 func函数return 出来的对象,这是一次拷贝,演示后两次拷贝的优化效果

结果:

 

解释:后两次拷贝优化成了一次

 ④:不在一行的的构造+构造

A func()
{A aa;return aa;
}int main()
{A aa2;aa2 = func();return 0;
}

解释:

a:A aa2是调用一次构造 

b:func 则进入函数,A aa 是一次构造 

c:return aa 是一次拷贝

d: 函数返回的对象给 aa2 是一次赋值(两个存咋的对象用 = 叫作赋值)

这个对前两次的构造进行展示,因为不是一行上的连续构造,所以不进行优化

结果:

总结:

一行上连续的构造 + 构造 =  一次构造 

一行上连续的构造 + 拷贝 =  一次构造

一行上连续的拷贝 + 拷贝 =  一次拷贝


http://www.mrgr.cn/news/51665.html

相关文章:

  • 本地如何使用Pycharm连接远程服务器调试torchrun
  • GitHub每日最火火火项目(10.16)
  • C语言之练习题
  • 一款非常有用且高效的国产的Linux运维面板:1Panel介绍
  • Opencv形态学的膨胀操作、开运算与闭运算、梯度运算、礼帽与黑帽操作
  • [Java基础] 流程控制
  • 【STM32单片机_(HAL库)】6-6-2【串口通信UART、USART】【蓝牙遥控插座项目】项目实现
  • pandas 数据分析实战
  • 字典树 计数问题(含 2022 icpc杭州 K)
  • awk工具的基本使用
  • 十二、Python基础语法(字符串str-上)
  • k8s系列-Rancher 上操作的k8s容器网络配置总结
  • Leetcode——数组:螺旋矩阵59.螺旋矩阵
  • 什么是领域驱动设计(DDD)?为什么需要领域驱动设计?
  • BAT脚本修改指定文件夹的图标,文件夹图标不变
  • 自定义树形结构转换,Hutool的TreeUtil工具
  • 算法之排序
  • 我只是一个不务正业的程序媛
  • 怎么给PPT文件设置文字动画效果,提高美观度
  • 选择排序,插入排序,快速排序的java简单实现