深度解析前置++i和后置i++的效率

15 篇文章 0 订阅
i++(后置)和++i(前置)。二者的语义是有区别的,前者先将其值返回,然后其值增1;后者则是先将值增1,再返回其值。
i++; //后置
++i; //前置
注意这里的前置和后置是说的运算符。
二者的语义则是一样的,都是将原值增1。但是对于一个 非内建类型 ,在重载这两个操作符后,单独使用在性能方面是否有差别?来考察它们的实现
先看下面这个返回对象的分析:
class C
{
public:
int i;
C &operator = (C &o)    //赋值
{
i = o.i;
cout<<"C &operator = (C &o) "<<i<<endl;
return *this;
};
C(int p)        //构造
{
i = p;
cout<<"C() "<<i<<endl;
};
~C()            //析构
{
cout<<"~C() "<<i<<endl;
};
C(C &o)        //拷贝构造
{
i = o.i*10;
cout<<"C(C &o) "<<i<<endl;
};
};

C fun1()
{
return C(1);
}

C fun2()
{
C o(2);
return o;
}

void main()
{
C o(3);
cout<<"---fun1---"<<endl;
o = fun1();
cout<<"---fun2---"<<endl;
o = fun2();
cout<<"---main---\no.i = "<<o.i<<endl;
system("PAUSE");
}
运行结果
C() 3
---fun1---
C() 1//构造函数
C &operator = (C &o) 1//赋值函数
~C() 1//析构函数
---fun2---
C() 2//构造函数
C(C &o) 20//拷贝构造函数
~C() 2//析构函数
C &operator = (C &o) 20//赋值函数
~C() 20//析构函数
---main---
o.i = 20
请按任意键继续. . .

可见.fun1内共生成了一个临时对象.函数调用顺序是
return用的临时对象的构造->赋值运算传值->临时对象的析构

fun2内共生成了两个临时对象.效率较低,但便于修改.函数调用顺序是
fun2内局部对象的构造->return用的临时变量的拷贝构造->局部对象的析构->赋值运算传值->临时对象的析构。

在来看看这样一个例子:
class Point//定义一个点的类
{
private:
int x,y;

public:
。。。。。。。
Point operator++(int);
Point& operator++();
~Point(){};//析构
};
//-------------Point函数-----------------
Point& Point::operator++()//前置,返回对象的引用
{
++ x;
++ y;
return *this;

}
Point Point::operator ++(int)//后置,返回对象
{
Point temp=*this;
++(*this);
return temp;

}
Point A;
A++;++A
对于后置i++,
1,我们显式创建一个tmp临时对象,                
语句:Point temp=*this;
2,将temp对象返回,返回过程中调用Copy cotr创建一个返回对象,              
语句:return tmp;
前置的++A只需要将自身返回即可,只需返回一个引用
如果调用后置A++,意味着需要多生成两个对象,分别是函数内部的局部变量和存放返回值的临时变量。
为了清晰的理解上面的内容,写了个完成的测试类。读者调试运行就一目了然了。
#include <iostream>
using namespace std;
//-------------Point定义-----------------
class Point
{
public:
int x,y;

public:
Point &operator=(Point &apoint)//赋值
{
x=apoint.x;
y=apoint.y;
cout<<"Point &operator = (Point &apoiont) "<<endl;
return *this;
}
Point(int xx=0,int yy=0):x(xx),y(yy)//构造
{
cout<<"Point Constructor!";
cout<<x<<","<<y<<endl;

}
~Point()//析构
{ cout<<"~Point() "<<endl;}

Point(Point& temp) //拷贝构造!

x=temp.x;
y=temp.y;
cout<<"Copy Ctor!";
cout<<x<<","<<y<<endl;

};
Point operator++(int);
Point& operator++();

};
//-------------Point函数-----------------
Point& Point::operator++()//前置
{
x++;
y++;
return *this;

}
 
Point Point::operator ++(int)//后置
//这里的形参类型int只是编译器区分前置和后置的区别,所以只给了类型.
{
Point temp;//这里可以直接写成Point temp=*this;试试,这里只是为了让结果看的更加仔细。
temp=*this;
cout<<"后置i++"<<endl;
++*this;
return temp;

}
 
//-------------Main函数-----------------
void main()
{
Point A(3,5);
cout<<"++A开始了"<<endl;
++A;
cout<<"A++开始了"<<endl;
A++;
cout<<A.x<<","<<A.y<<endl;//方便测试,不幸的把x,y设置成了public类型.
cout<<"对象的生存期"<<endl;
}
运行结果:
Point Constructor!3,5
++A开始了
A++开始了
Point Constructor!0,0
Point &operator = (Point &apoiont)
后置i++
Copy Ctor!4,6
~Point()
~Point()
5,7
对象的生存期
~Point()
Press any key to continue

      如果返回引用的话,就没有这么多临时变量了.但是返回值为某一类型的引用一般是为了实现链式表达.而且有下面几点要注意:
1.不能返回局部变量的引用.因为在外面的对象接到这个引用之前就已经被析构掉了.它只能接到一个空对象
2.不要返回函数内部new分配的内存的引用.因为delete的安排会变得麻烦,而且很容易造成内存泄漏或访问到已经delete的对象
3.可以返回类成员的引用,但最好是const
4.不要返回静态变量的引用.比如,operator+返回了静态变量的引用.((a+b) == (c+d))会永远为true而导致错误

参考:
1.关于返回对象
http://www.cnblogs.com/iceqq/archive/2009/05/16/1458095.html
2. 临时对象(4)
http://book.51cto.com/art/201006/203584.htm

3.Effective C++


http://hi.baidu.com/wust/blog/item/8466023b84cf19e714cecbe2.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值