编译器对临时变量的优化--简单理解

2010-7-6

烛秋

2010-8-20整理

一、问题来源

  之前对NRV优化做了一点总结,还有所欠缺,只分析了 A b = f();的情况,没有去分析A b; b = f();的情况。又想起之前看过的书,对产生临时对象的讲解都是假设了编译器没有进行优化,然后说要提高C++程序性能,必须尽量的少使用返回对象,因为那样才不会产生临时对象。多使用引用/指针可以减少临时对象的产生,提高程序性能,这个观点没有错。但事实上很多编译器多做了优化,使得临时对象的产生减少了很多,打算以最简单的例子对编译器的优化做简单的理解。

代码:

/*
*/
/////////////////////////////////////////////////
/*
*命令行编译:
*g++ -o 1.exe 1.cpp
*/
/////////////////////////////////////////////////
/////////////////////////////////////////////////
#include <iostream>
#include <cstring>
using namespace std;
class A
{
public:
	A()
	{
		cout<<"construct"<<endl;
		strcpy(name,"zhangsan");
	}
	~A()
	{
		cout<<"destruct"<<endl;
	}
	A(const A& temp)
	{
		cout<<"copy"<<endl;
		strcpy(name,temp.name);
	}
	A& operator= (const A& temp)
	{
	    cout << "operator=" << endl;
	    strcpy(name, temp.name);
	    return *this;
	}
private:
	char name[16];
};
////////////////////////////
A f()
{
	cout<<"------------function f----------"<<endl;
	A b;
	return b;
}
////////////////////////////
int	main()
{
	A b;
	b = f();//A b(f());
	return 0;
}
/*
测试输出结果:
VS2005release模式//优化了
construct
------------function f----------
construct
operator=
destruct
destruct
*/
/*
vs2005Debug模式//未优化,跟书上的一致
construct
------------function f----------
construct
copy
destruct
operator=
destruct
destruct
*/

二、分析

  对于采用了NRV优化的编译器来说(例如:VS的release模式、G++),没有临时对象产生。但是对于debug模式下,会产生临时对象。

 Debug模式下做法是:局部对象-->临时对象-->外部对象。

 说明:第一个箭头调用拷贝构造函数产生了临时对象,第二个箭头调用operator=操作。

 Release模式下做法是:局部对象-->外部对象。

 说明:调用operator=操作

  从图1和图3可以看到,调用operator=操作都是在main()函数中进行,这就意味着operator=的右值必须是存在的对象。在debug模式下,临时对象的地址是在main()函数作用域中,这没有问题。在release模式下,“临时对象"和局部对象合并了。原因如下:局部对象是在函数f()中创建的,但是它的地址空间是main()函数的,从图3和图4可以看到创建局部对象时,使用的地址空间是在main()中申请的“临时对象”空间。这点跟上一篇文章分析的NRV优化类似,都是把临时对象的地址传递进函数f(),然后局部对象就在这个地址上创建,这样就减少了拷贝构造函数的调用。

   

三、OD调试截图

 图 1 debug模式main()函数

图 2 debug模式f()函数

 

图 3 release模式main()函数 

图 4 release模式f()函数

 

posted on 2010-08-21 00:07  烛秋  阅读(2474)  评论(0编辑  收藏  举报