结论:优先使用 ++i 和 --i 以提高运行效率
虽然大家都知道 i++/i-- 是先使用再自加减,而 ++i/--i 则是先自加减再使用
首先回顾下:
C++中自加自减运算符的重载
自增运算符++
、自减运算符--
都可以被重载,但是它们有前置、后置之分。
以++
为例,假设 obj 是一个 CDemo 类的对象,++obj
和obj++
本应该是不一样的,前者的返回值应该是 obj 被修改后的值,而后者的返回值应该是 obj 被修改前的值。如果如下重载++
运算符:
CDemo & CDemo::operator ++ ()
{
//...
return * this;
}
那么不论obj++
还是++obj
,都等价于obj.operator++()
无法体现出差别。
为了解决这个问题,C++ 规定,在重载++
或--
时,允许写一个增加了无用 int 类型形参的版本,编译器处理++
或--
前置的表达式时,调用参数个数正常的重载函数;处理后置表达式时,调用多出一个参数的重载函数。来看下面的例子:
#include <iostream>
#include <vector>
using namespace std;
class MyInt
{
public:
MyInt(int i = 0) { n = i; }
MyInt & operator++();//前置++,++i
MyInt operator++ (int);//后置++,i++
//友元函数形式的函数重载
friend MyInt & operator --(MyInt &);//前置--,--i
friend MyInt operator --(MyInt &, int);//后置--,i--
friend ostream & operator<<(ostream &out, MyInt in); //重载输出运算符
//或者重载int运算符
operator int() {
cout << "重载了 << 运算符" << endl;
return n;
}
private:
int n;
};
MyInt & MyInt::operator++()
{
n = n + 1;
return *this;
}
MyInt MyInt::operator++(int)
{
//需要创建一个临时对象,保存之前的数据,然后再自加
MyInt temp(*this);
n = n + 1;
return temp;
}
MyInt & operator--(MyInt &i)
{
i.n = i.n - 1;
return i;
}
MyInt operator --(MyInt &i, int){
MyInt temp(i);//这里使用了默认拷贝构造函数
i.n = i.n - 1;
return temp;
}
ostream & operator<<(ostream &out, MyInt in)
{
cout << "重载了 << 运算符" << endl;
out << in.n;
return out;
}
int main(void) {
MyInt i(666);
cout << "i = "<< i++ << endl;
cout << "i = " << ++i << endl;
cout << "i = " << i-- << endl;
cout << "i = " << --i << endl;
return 0;
}
/*
*
*
i = 重载了 << 运算符
666
i = 重载了 << 运算符
668
i = 重载了 << 运算符
668
i = 重载了 << 运算符
666*/
再回到自加自减的源码实现:
// 前置自加自减
// ++i
T& T::operator++(){
++*this;
return *this;
}
// --i
T& T::operator--(){
--*this;
return *this;
}
//后置自加自减
T T::operator++(int){
T old(*this);
++*this;
return old;
}
T T::operator--(int){
T old(*this);
--*this;
return old;
}
自增自减的后缀形式所多花费的开销:
T old(*this);
这一句产生一个类型为T的临时对象 old, 并用原值*this进行初始化.当函数return的时候,又再次创建一个临时对象,并用old的值进行初始,之后,局部变量old被销毁.并用临时创建的变量对赋值符左边的变量进行赋值(如果有的话).赋值后,临时变量再次被销毁.
而前缀形式的自增自减呢?
首先函数内没有创建临时变量,故这方面的开销就节省了。其次,返回的是一个引用。故也节省了这时候创建销毁临时对象的开销.。
因此后缀式的自增自减,所多花费的开销是两次临时变量的创建,以及两次临时变量的销毁,如果自增自减的对象不是内建的数据类型,而一个类类型[当然,你首先得重载自增自减操作符, 那么这个开销可能会比较大,因为变成了两次构造函数以及两次析构函数的调用。
所以在调用代码的时候,要优先使用前缀形式,除非确实需要后缀形式返回原值。