c/c++:efficient c++,临时对象

说个题外话

#include <iostream>
using namespace std;

class A
{
public:
    char a;
    char b;
    char c;
public:
    A(char aa, char bb=97, char cc=97):a(aa),b(bb),c(cc){}
};

int main()
{
    A e=98;
    cout<<e.a<<e.b<<e.c<<endl;
    return 0;
}

 

对于 下面的 A e= 98;  是能够匹配到A的构造函数的,aa 需不需要默认值都可以,这样的声明会将 98 赋予第一个 参数,即aa 。

 

主要内容:

class Rational
{
    friend Rational operator +(const Rational &,const Rational &);
public:
    Rational(int a=0,int b=1):m(a),n(b){}
private:
    int m;
    int n;
};

 

对于对象定义:

Rational r1(100);
Rational r2 = Rational(100);
Rational r3= 100;

 

只有第一个r1 是不会创建临时变量的,另外两个都会。不过编译器优化了,所以3者效率一样。

 

对于类型不匹配:

Rational r;
r=100;

 

这样第二句会寻找Ratiaonal  的构造函数(如我上面写的那个题外话),然后再调用拷贝函数实现。

想禁止这用转换,可以再构造函数(对于其他什么函数都适用)前面加 explicit

class Rational
{
public:
    explicit Rational(int  a=0, int b=1):m(a),n(b){}
};

 

 

有时候调用函数时会产生临时变量的,如

void g(const string &s){}

g("message");

 

下面的调用函数中传递的是指针。

 

再按例子 Complex类

complex a,b;
for(int i=0;i<100;i++)
{
    a= i*b +1.0;
}

complex a,b;
complex one(1,0);
for(int i=0;i<100;i++)
{
    a= i*b +one;
}

 

上面部分中的1.0 需要不断的创建于销毁。

 

按值传递

一般的调用:

T t;
g(t);

 

编译器将需要创建T 类型的临时对象,并且用t 作为输入参数调用拷贝构造函数创建这个变量,然后以这个变量作为实参传递给个g(),然后返回时调用析构函数释放临时变量。

 

按值返回:

调用函数会创建变量保存返回值,如果有赋值语句就调用赋值函数,最后是释放临时变量。 

通过上一章可以消除在被调用函数中的临时变量 (RVO)。

至于消除当前函数的临时变量。就要考虑。

对于语句 s3=s1 +s2. 源函数会产生一个临时变量保存 s1+s2 的值。为什么会产生呢? 

这是两个操作 ,+  = ,对于s1+s2 部分没有权利修改s3 的值。(这是 = 的是功能)。

如果s3 有旧值时,不能将s3 作为这一临时变量,但如果s3 是新声明的,便能直接作为该变量,这样就省了一个临时变量。

写法:

//有临时变量
string s1= "Hello ";
string s2= "World ";
string s3;
s3=s1+s2;
//无临时变量
string s1= "Hello ";
string s2= "World ";
string s3=s1+s2;

 

 

至于在s3 有旧值的情况下,可以这样来避免创建临时变量。

//有临时变量
string s1,s2,s3,s4;
s1=s2+s3+s4;
//无临时变量
s1=s2;
s1+=s3;
s1+=s4;

 

 

要点:

1.临时对象会以构造函数和析构函数的形式降低一半的性能。

2.将构造函数声明为 explicit,可以阻止编译器幕后使用类型转换。

3.编译器常常创建临时对象来解决类型不匹配问题。通过重载可以避免这种情况。

4.如果肯尼个,尽量避免使用对象拷贝(应该指函数调用的时候),按引用传递和返回对象。

5.在<op>可能是“+-*/”的地方,使用 <op>=运算符可以消除临时对象。

 

posted @ 2012-07-14 15:47  A_zhu  阅读(755)  评论(0编辑  收藏  举报