临时对象

来源:互联网 发布:手机版会员积分软件 编辑:程序博客网 时间:2024/05/21 16:56

说个题外话

复制代码
#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>=运算符可以消除临时对象。

0 0
原创粉丝点击