<C++> 编译器优化问题

int main()
{
	string s = "hello";
	return 0;
}

这几段代码理论上应该是先使用hello创建一个临时对象,然后用临时对象拷贝构造s对象,但是在现代大多数编译器下,都会优化掉临时对象的创建,直接用这个字符串构造对象s。

在谈编译器优化的时候要说明,编译器的优化并不是绝对的,有的编译器会做出优化但是有的编译器又没有优化。因为这个是C++标准未定义的。
以下的测试环境是VS2019;

编译器的优化行为一般发生在一个表达式中,如果产生了一个临时对象,然后又用这个临时对象去构造一个对象,可能优化成直接去构造这个对象,就不会产生临时对象了。
总结说就是:在一个表达式中,连续多个构造函数(构造和拷贝构造)可能会被优化成一次,优化掉的一般都是临时对象或者匿名对象的创建。注意如果是构造函数和赋值,这是不能优化的(例如,拷贝构造+赋值这是不可优化的),必须是多个构造函数。

下面我们使用几段代码来测试编译器优化,首先定义这个类,每调用一次构造函数或者是拷贝构造或者是析构和赋值运算符重载就会打印一次。

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	A(const A& a)
	{
		cout << "A(const A& a)" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}
	A& operator=(const A& a)
	{
		cout << "A& operator=(const A& a)" << endl;
	}
private:

};

上代码:

A test1()
{
	static A aa;
	return aa;
}

int main()
{
	A a1 = test1();
	return 0;
}

分析:首先,静态对象只会在第一次调用test1函数的时候调用一次构造函数。全局对象是在main函数调用之前构造的。上面代码首先调用了test1函数构造了aa对象,然后使用值返回用aa对象拷贝构造了一个临时对象,然后调用拷贝构造函数构造出来了a1对象,所以一共调用了一次构造两次拷贝构造。最后应该还有三次析构。

 这里只调用了一次构造函数和一次析构函数。所以编译器进行了优化,那么优化的地方在哪呢?少了一次拷贝构造说明返回值的时候没有拷贝构造临时对象,而是直接拷贝构造出来了a1对象。但是上面是static对象,出来函数作用域不会销毁所以可以使用传引用返回。


 这里再看如果使用赋值,因为赋值和上段代码的拷贝构造是不同的,这里的赋值是不可以优化的。所以就会出现两次构造,a1和aa然后使用aa拷贝构造临时对象,最后调用了赋值运算符重载函数。

当然如果使用传引用,返回那么就可以减少一次拷贝构造

 所以如果对象出了函数作用域是不会销毁的话,尽量使用传引用返回。

总结:在一个表达式中,连续多个构造可能会被编译器优化成一次

再来看最后一个例题:

A test(A aa)
{
	A copy1(aa);
	A copy2 = copy1;
	return copy2;
}

int main()
{
	A a;
	A ret = test(test(a));
	return 0;
}

来看这段代码,调用了几次拷贝构造函数呢?

 这里是图解,如果假设编译器没有优化,是总共调用了9次拷贝构造,两个方框代表了两个临时对象。
首先使用a拷贝构造了形参aa,然后aa拷贝构造了copy1,copy1拷贝构造了copy2(注意这里虽然是等号也是拷贝构造,因为这里的copy2还是对象创建初始化阶段,只有对象创建出来之后再给对象赋值才是赋值)copy2拷贝构造了一个临时对象作为内部test()的返回值,然后传参给外部test(),作为外面test()的实参,使用这个临时对象1拷贝构造了aa然后aa重复上面再函数中的拷贝构造,返回值,因为是值返回所以先再main函数的栈帧内开辟一个临时对象2,调用了一次拷贝构造,然后再用哦这个临时对象2,拷贝构造了ret对象。至此总共调用了9次拷贝构造函数。

下面来看一下结果:

 结果是7次拷贝构造,想必优化了那两个拷贝构造应该很明了了,就是优化了两个临时对象的拷贝构造,直接使用了返回值去拷贝构造目标对象。
因为这里的返回值和传参可以看作是一个表达式,并且有多个构造函数,所以就发生了优化。

其次关于传值返回,如果是对象比较小话一般是使用寄存器保存返回值然后返回。如果对象比较大就会拷贝这个对象一次,然后再用拷贝出来的临时对象作为返回值,所以临时对象一定不在test栈帧中,一般是在需要接受test返回值的栈帧之中,临时对象具有常属性,只读不可修改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值