浅析临时对象


1、QPixmap pixmap(WIN_SATELLITE_EDIT_W, WIN_SATELLITE_EDIT_H);	//生成临时的对象
	if(pixmap.load(filename, "png")) 
	{
		QSize fitsize(WIN_SATELLITE_EDIT_W,WIN_SATELLITE_EDIT_H); //生成临时对象
		QPixmap fitpixmap = pixmap.scaled (fitsize, Qt::IgnoreAspectRatio, Qt::FastTransformation);
		pal.setBrush(QPalette::Window,QBrush(fitpixmap));
		setPalette(pal);
	}
	
2、浅析临时对象

   什么是临时对象?
   定义:当且仅当离开一段上下文(context)时在对象上执行的仅有的操作是析构函数时,  
   一个对象被看成是临时的。临时对象很多情况下我们是看不到的,是编译器自己完成的,生存期极短。  
  
   这里上下文可能是一个表达式,也可能是一个语句范围,例如函数体。  
  
面试题中经常会考到C++的临时对象创建的相关问题 所以个人再次浅析一下三种常见的临时对象创建情况  
  
以下仅是个人理解 如有错误  还望大家指正            //   
  
所有代码均在xp sp3 vc++ 6.0测试通过   不同的编译器和环境结果会有所不同  
  
  1,以值的方式给函数传参;    //****   
  
  2,类型转换;//****   
  
  3,函数需要返回一个对象时;//****   
   
那么下面就让我们一个一个来看  
   
<STRONG><SPAN style="FONT-SIZE: 18px">  一,以值的方式给函数传参。//*****************//</SPAN></STRONG>   
   
  我们知道函数传参有两种方式。  
  
1,按值传递;//按值传递时,首先将需要传给函数的参数,调用拷贝构造函数创建一个副本,   
             //所有在函数里的操作都是针对这个副本的,也正是因为这个原因,   
             //在函数体里对该副本进行任何操作,都不会影响原参数。   
2,按引用传递。  
            //引用则不然  它是对象的本身 只是一个别名而已   
  
接着那么我们看以下例子:  
   
#include <stdio.h>   
class TempObj  
    {  
    public:  
        int m_Number;  
        int m_Size;  
    public:  
        TempObj(TempObj& to)//拷贝构造函数   
            {   
            printf("Copy function!\n");  
            m_Number = to.m_Number;  
            m_Size = to.m_Size;  
            };  
        TempObj(int m = 0,int n = 0);//带有默认参数的构造函数   
        ~TempObj(){};//析构函数   
        int GetSum(TempObj ts);  
    };  
TempObj::TempObj(int m , int n)  
    {  
    printf("Construct function!\n");  
    m_Number = m;m_Size=n;  
    printf("m_Number = %d\n",m_Number);  
    printf("m_Size = %d\n",m_Size);  
    }  
int TempObj::GetSum(TempObj ts)  
    {  
    int tmp = ts.m_Number + ts.m_Size;  
    ts.m_Number = 1000;           //此时修改的是tm的一个副本ts而已 所以不会影响对象tm   
  
    return tmp;              //注意此处   
    }  
void main()  
    {  
    TempObj tm(10,20);  
    printf("Sum = %d \n",tm.GetSum(tm));  
    printf("tm.m_Number = %d \n",tm.m_Number);  
    char c=getchar();  
    }  
  
******************************************************************************************  
输出结果:  
  
Construct function!  
m_Number = 10  
m_Size = 20  
Copy function!  
Sum = 30  
tm.m_Number = 10  
请按任意键继续. . .  
*******************************************************************************************  
我们看到有调用了拷贝构造函数,这是tm在传给GetSum做参数时:  
  
1,调用拷贝构造函数来创建一个副本为GetSum函数体内所用。  
  
2,在GetSum函数体内对tm副本进行的修改并没有影响到tm本身。  
   
解决办法:  
  针对第一种情况的解决办法是传入对象引用(记住:引用只是原对象的一个别名(Alias)),  
我们将GetSum代码修改如下:  
   
int TempObj ::GetSum(TempObj & ts)  
{  
    int tmp = ts.m_Number + ts.m_Size;  
    ts.m_Number = 1000;     //此时通过ts这个引用对象本身   
    return tmp;  
}  
*******************************************************************************************  
输出结果  
  
Construct function!  
m_Number = 10  
m_Size = 20  
Sum = 30  
tm.m_Number = 1000  
请按任意键继续. . .  
*******************************************************************************************  
可以通过输出看通过传递常量引用,减少了一次临时对象的创建。这个改动也许很小,  
  
但对多继承的对象来说在构建时要递归调用所有基类的构造函数,这对于性能来说是个很大的消耗,  
  
而且这种消耗通常来说是没有必要的。  
 <STRONG><SPAN style="FONT-SIZE: 18px">  
  
 二、类型转换生成的临时对象。//****************************//</SPAN></STRONG>   
   
  我们在做类型转换时,转换后的对象通常是一个临时对象。编译器为了通过编译会  
  
创建一些我们不易察觉的临时对象。再次修改如上main代码:  
   
void main()  
{  
 TempObj tm(10,20),sum;  
 sum = 1000;  //调用TempObj(int m = 0,int n = 0)的构造函数   
 printf("Sum = %d \n",tm.GetSum(sum));  
}  
*******************************************************************************************  
输出结果:  
Construct function!  
m_Number = 10  
m_Size = 20  
Construct function!  
m_Number = 0  
m_Size = 0  
Construct function!  
m_Number = 1000  
m_Size = 0  
Sum = 1000  
请按任意键继续. . .  
*******************************************************************************************  
main函数创建了两个对象,但输出却调用了三次构造函数,这是为什么呢?  
关键在 sum = 1000;这段代码。本身1000和sum类型不符,  
但编译器为了通过编译以1000为参数调用构造函数创建了一下临时对象。  
   
解决办法:  
  我们对main函数中的代码稍作修改,将sum申明推迟到“=”号之前:  
   
void main()  
{  
    TempObj tm(10,20);  
    TempObj sum = 1000;  //调用TempObj(int m = 0,int n = 0)构造函数   
    printf("Sum = %d \n",tm.GetSum(sum));  
}  
*******************************************************************************************  
输出结果:  
  
Construct function!  
m_Number = 10  
m_Size = 20  
Construct function!  
m_Number = 1000  
m_Size = 0  
Sum = 1000  
请按任意键继续. . .  
*******************************************************************************************  
只作了稍稍改动,就减少了一次临时对象的创建。  
1,此时的“=”号由原本的赋值变为了构造。  
2,对Sum的构造推迟了。当我们定义TempObj sum时,  
在main的栈中为sum对象创建了一个预留的空间。而我们用1000调用构造时,  
此时的构造是在为sum预留的空间中进行的。因此也减少了一次临时对象的创建。  
   
<STRONG><SPAN style="FONT-SIZE: 18px">  
三、函数返回一个对象。 //***********************//</SPAN></STRONG>   
   
  当函数需要返回一个对象,他会在栈中创建一个临时对象,存储函数的返回值。看以下代码:  
   
#include <stdio.h>   
#include <windows.h>   
class TempObj  
    {  
    public:  
        int m_Number;  
    public:  
        TempObj(TempObj& to) //Copy Constructior Function   
            {   
            printf("Copy Constructor Function\n");  
            m_Number = to.m_Number;  
            };  
        TempObj& operator=(TempObj& to) //Assignment Copy Function   
            {  
            printf("Assignment Copy Function\n");  
            m_Number = to.m_Number;  
            return *this;  
            }  
        TempObj(int m = 0);  
         ~TempObj(){};  
    };  
TempObj::TempObj(int m)   
    {  
    printf("Construct function!\n");  
    m_Number = m;  
    printf("m_Number = %d\n",m_Number);  
    }  
TempObj Double(TempObj& to)  
    {  
    TempObj tmp;      //构建一个临时对象   
    tmp.m_Number = to.m_Number*2;  
    return tmp;        //返回一个对象   
    }  
void main()  
    {  
    TempObj tm(10),sum;  
    printf("\n\n");  
    sum = Double(tm);  
    printf("\n\n");  
    printf("sum.m_Number = %d \n",sum.m_Number);  
    system("pause");  
    }  
*******************************************************************************************  
输出结果:  
  
Construct function!  
m_Number = 10  
  
Construct function!  
m_Number = 0  
  
Construct function!  
m_Number = 0  
  
Copy Constructor Function  
Assignment Copy Function  
  
sum.m_Number = 20  
请按任意键继续. . .  
*******************************************************************************************  
 
 sum = Double(tm);  
这条语句竟生成了两个对象 我们现在将这条语句逐步分解一下:  
    1,我们显式创建一个tmp临时对象,                 
      语句:TempObj tmp;  
    2,将temp对象返回,返回过程中调用Copy 创建一个返回对象,                
      语句:return tmp;  
    3,将返回结果通过调用赋值拷贝函数,赋给sum         
      语句: sum = 函数返回值;(该步并没有创建对象,只是给sum赋值)  
   
tm.Double返回一个用拷贝构造函数生成的临时对象,并用该临时对象给sum赋值.  
    
  第2步创建的返回对象是难以避免的,你或许想可以返回一个引用,  
但你别忘记了在函数里创建的局部对象,在返回时就被销毁了。  
这时若再引用该对象会产生未预期的行为。  
解决方法:  
  
  我们将对象直接操作返回对象,再结合上面的减少临时对象的方法,  
将函数Double的代码,及main函数中的代码修改如下:  
//*****************代码段1***********************   
TempObj Double(TempObj& to)  
{  
    return to.m_Number*2;  
}  
  
//******************代码段2*********************   
TempObj  _ret  
void Double(TempObj & to)  
{  
    _ret.m_Number = to.m_Number*2;  
}  
代码段1和代码段2相似  
//****************************************   
void main()  
{  
    TempObj tm(10);  
    printf("\n\n");  
    TempObj  sum= Double(tm);  
    printf("\n\n");  
    printf("sum.m_Number = %d \n",sum.m_Number);  
}  
  
*******************************************************************************************  
输出结果:  
Construct function!  
m_Number = 10  
  
Construct function!  
m_Number = 20  
  
sum.m_Number = 20  
请按任意键继续. . .  
*******************************************************************************************  
发现减少了一次构造函数调用(tmp),一次拷贝构造函数(tmp拷贝给返回对象)调用  
 和一次赋值拷贝函数调用,这是因为:  
  
 返回对象直接使用为sum预留的空间,  
所以减少了返回临时对象的生成——返回对象即是sum,  
返回对象的创建即是sum对象的创建

转载于:https://my.oschina.net/mavericsoung/blog/113395

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值