关于编译器对连续的构造+拷贝构造/连续的拷贝构造的优化

一道很坑的题_(:з」∠)_:

以下代码共调用多少次拷贝构造函数?

// 《深度探索C++对象模型》
Weight f(Weight u)
{
	Weight v(u);
	Weight w = v;

	return w;
}

int main()
{
	Weight x;
	Weight ret = f(f(x));
	return 0;
}

1 匿名对象

为了让大家更好地理解上面那道题,我们先来介绍一下什么是匿名对象?
匿名对象可以理解为是一个临时对象,一般系统自动生成的,如你的函数返回一个对象,这个对象在返回时会生成一个临时对象。
语法:类名();
注意:
(1)如果生成的匿名对象在外面没有对象等待被其实例化,生命周期只在它定义的那一行
(2)如果生成的匿名对象在外部有对象等待被其实例化,此匿名对象的生命周期就变成了外部对象的生命周期.
我借助以下代码调试向大家说明:

#include <iostream>
using std::cout;
using std::cin;
using std::endl;

class Weight
{
public:
	Weight()
	{
		cout << "Weight()" << endl;
	}

	Weight(const Weight& w)
	{
		cout << "Weight(const Weight& w)" << endl;
	}
	
	~Weight()
	{
		cout << "~Weight()" << endl;
	}
	
	Weight& operator=(const Weight& w)
	{
		cout << "Weight& operator=(const Weight& w)" << endl;
		return *this;
	}
	
	void print()
	{
		cout << "2022-5-25" << endl;
	}
};

// 《深度探索C++对象模型》
Weight f(Weight u)
{
	Weight v(u);
	Weight w = v;

	return w;
}

int main()
{
	Weight x;
	Weight();
	f(x);
	return 0;
}

在这里插入图片描述
我们发现44行这个匿名对象调了构造函数之后,马上又调了析构函数

Weight y = Weight();	// 生命周期变成y的生命周期。

在这里插入图片描述

2.匿名对象的用处

我们平时调用类的成员函数,是不是先定义一个对象,通过对象去调用。
匿名对象还可以这样调用:
在这里插入图片描述
还有,如果你只是单纯的想要传参,也可以用匿名对象:
在这里插入图片描述
但是我们发现左边传参的方式调用了4次拷贝构造,而右边传参的方式调用了3次拷贝构造。
为什么?因为编译器优化了,编译器会在一个步骤里面,比如说一个表达式里面,如果出现连续的构造+拷贝构造或者连续的拷贝构造,编译器会把它们优化。
左边没的说,因为是分开的,先构造了一个对象,然后把这个对象传参又调用了拷贝构造。
右边是构造了匿名对象之后立马作为参数传参,这个时候编译器就会把它们合二为一,直接构造传参的对象。

还记得我们以前说的拷贝构造的两种方式吗?

class A 
{
public:
	A(int x)
	{}
};

int main()
{
	A a1(1);
	A a2 = 2; // A(2)  -> A a2(A(2))   优化:直接构造
	return 0;
}

关于 A a2 = 2;这行代码,它会先拿2构造一个匿名对象(也叫临时对象),然后才会拿这个对象去拷贝构造一个a2。这个时候胆大的编译器也会优化,直接构造a2.

注意:C++标准并没有规定是否优化,完全取决于编译器,不过新一点的编译器一般都会做这个优化。

3.题解

3.1 铺垫

如果是以下的代码,我们的程序会调用几次拷贝构造?
在这里插入图片描述

ok,我们先自己来算一下。
x传参拷贝构造1次,33、34行各拷贝构造1次,传值返回拷贝构造1次,41返回的结果又拷贝构造给ret,又是1次。是不是应该总共5次呀!

ok,我们看运行结果:
在这里插入图片描述
怎么回事?
在这里插入图片描述
本来是不是应该这样啊,但是大家注意,41行是不是连续的拷贝构造啊,编译器会把它合二为一,相当于直接用w去拷贝构造ret了。

如果大家还是不能确信,请看下图:
在这里插入图片描述
这个返回来的w的临时对象就是赋值给ret,因为ret对象已经存在。阻断了编译器的优化。

3.2 解题

在这里插入图片描述
所以这道题总共一个调用了7次拷贝构造函数,我们运行一下看是不是:
在这里插入图片描述
哈哈,你答对了吗?(:з」∠)
在这里插入图片描述

  • 36
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 29
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuucho

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值