C++性能分析之临时对象


以前说过:C++临时对象的创建和销毁对程序性能有一定的影响,尤其当该对象的类处于一个复杂继承体系的末端,或者该对象包含

很多成员变量对象时,对程序的影响尤为明显。


避免创建不必要的对象,不仅意味着在编程时,主要减少显示出现在源码中的对象创建,还有在编程过程中,编译器在某些特定情况下

生成的隐士的临时对象,这些对象创建并不出现在源码中,而是由编译器在编译过程中“悄悄生成”,并在适当的时期进行销毁。

临时变量的概念:

voidswap(int*px,int*py)

{

inttemp; //这时的temp临时变量(并不是这里说的“临时对象”)

temp= *px;

*px= *py;

*py= temp;

}

我们现在讨论的临时对象并不会出现在源码中:

首先我们先看如下的代码:

#include"stdafx.h"

#include<iostream>

usingnamespacestd;

const intsize= 5;


classMatrix

{

private:

intmVal[size][size];

public:

//Matrix(void){}

Matrix(intm=1)

{

cout<<"Matrix::Matrix()"<<endl;

for(inti=0;i<size;i++)

for(intj=0;j<size;j++)

mVal[i][j]= m;

}


Matrix(constMatrix&src)

{

cout<<"Matrix(constMatrix& src)"<<endl;

memcpy(this,&src,sizeof(Matrix));

}


Matrix&operator=(constMatrix&src)

{

if(this== &src)

return*this;

cout<<"Matrix&operator=(const Matrix& src)"<<endl;

memcpy(this,&src,sizeof(Matrix));

return*this;

}

~Matrix(){}

friendconstMatrixoperator+(constMatrix&,constMatrix&);

};


constMatrixoperator+(constMatrix&left,constMatrix&right)

{

Matrixsum;

for(inti=0;i<size;i++)

for(intj=0;j<size;j++)

sum.mVal[i][j]= left.mVal[i][j]+ right.mVal[i][j];

returnsum;

}


int_tmain(intargc,_TCHAR*argv[])

{

Matrixa(1),b(2),c;

c= a+b;

return0;

}


从控制台我们可以看出有四个构造函数,有一个拷贝函数,还有一个赋值运算。

我们分析下:首先主函数Matrixa,b,c等三个,第四个应该是Matrixsum的构造函数。

接下来是Matrix(constMatrix&src)的输出 这时应该是a+b返回时通过Matrix拷贝函数构造

最后是Matrix&operator=(constMatrix&src)的输出,这时比较明显,是由于=的使用。

int_tmain(intargc,_TCHAR*argv[])

{

Matrixa(1),b(2);

Matrixc= a+b;

return0;

}

当我们将主函数里面的代码写成这样的时候,会明显少一个输出,

此时并不会执行赋值运算符,



这时,我们发现在使用重载运算符+号的时候,明显出现了一个临时对象,那么我们如何规避呢?

这是一个很重要的问题,值得研究与讨论


产生临时对象的一般来说会有如下两种场合。

1>当实际调用函数时传入的参数与函数定义的声明的变量类型不匹配

2>当函数返回一个对象时


有时候因为类型不匹配而生成临时对象的情况,下面写一段代码:

#include"stdafx.h"

#include<iostream>

usingnamespacestd;

classTest

{

private:

intm;

intn;

public:

Test(intm1=0,intn1=1):m(m1),n(n1){}

~Test(){}

};


int_tmain(intargc,_TCHAR*argv[])

{

Testr;

r= 2;

return0;

}

在执行上段代码r=2,编译器会在此处合成一个operator=(constTest&),并且执行逐位拷贝形式的赋值操作,

但是右边的一个整型常量并不是一个Test对象,乍看此处是无法编译成功的,但是C++编译器总是寻找合适的

转换路径,以满足编译的需要。

可能这时编译器会通过调用Test::Test(2,1)生成一个临时对象,进而使得编译能够通过。

Test(intm1=0,intn1=1):m(m1),n(n1){

cout<<m<<" "<<n<<endl;

}

我们将构造函数的里面内容显示出来,可以看到的确显示了这个数据。

从上面的例子可以看见,C++编译器为了成功编译某些程序,往往会在私底下悄悄生成很多“不为人知”的函数或者对象。

那么我们如何阻止这种事情的发生呢?

我们在构造函数里面可以使用关键字explicit 此时上序代码则会出现问题。


如果我们还想这样实现 则可以重载=运算符。

但是这样做会让代码显得比较臃肿。


还有一种往往导致临时对象的产生,即当一个函数返回的是某个非内建类型的对象时,这时因为返回结果必须要有一个

地方存放。所以编译器会从调用该函数的函数对象堆栈中开辟空间,并用返回值作为参数调用该对象所属类型的拷贝

构造函数在此空间中生成该对象。在被调用函数结束并返回时,可以继续利用此对象。

#include"stdafx.h"

#include<iostream>

usingnamespacestd;

const intsize= 5;


classTest

{

private:

intmVal;

intnVal;

public:

Test(intm=1,intn=2):mVal(m),nVal(n)

{

cout<<"Test::Test()"<<endl;

}


Test(constTest&src):mVal(src.mVal),nVal(src.nVal)

{

cout<<"Test(constTest& src)"<<endl;

}


Test&operator=(constTest&src)

{

if(this== &src)

return*this;

mVal= src.mVal;

nVal= src.nVal;

cout<<"Test&operator=(const Test& src)"<<endl;

return*this;

}

~Test(){}

friendconstTestoperator+(constTest&,constTest&);

};


constTestoperator+(constTest&left,constTest&right)

{

cout<<"start"<<endl;

Testtemp;

temp.mVal= left.mVal+right.mVal;

temp.nVal= left.mVal+right.nVal;

cout<<"end"<<endl;

returntemp;

}


int_tmain(intargc,_TCHAR*argv[])

{

Testa(1),b(2);

Testc= a+b;

return0;

}


当这样使用时会减少一个临时对象的产生(上面介绍过)

constTestoperator+(constTest&left,constTest&right)

{

cout<<"start"<<endl;

returnTest(left.mVal+right.mVal,right.nVal+left.nVal);

}

这是又会出现一个现象会省去临时temp计算的多余。

大家对于临时对象一定要慎重。例如以下的代码:

stringa="123",b="456789";

constchar*str;

if(strlen(str=(a+b).c_str())>5)

cout<<str<<endl;

return0;

以上代码会有一些问题,cout中的str是否还是非法的!!(声明周期)


临时对象!!!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值