设为首页 加入收藏

TOP

建议12:优先使用前缀操作符
2013-10-07 14:47:42 来源: 作者: 【 】 浏览:68
Tags:建议 优先 使用 前缀 操作

建议12:优先使用前缀操作符

也许从开始接触C/C++(www.cppentry.com)程序的那天起,就记住了前缀和后缀运算,知道了++的前缀形式是“先加再用”,后缀形式是“先用再加”。前缀和后缀运算是C和C++(www.cppentry.com)语言中的基本运算,它们具有类似的功能,区别也很细微,主要体现在运行效率上。

分析下面的代码片段:

  1. int n=0m=0;  
  2. n = ++m; /*m先加1, 之后赋给n*/  
  3. cout << n << m; /*结果:1 1*/ 

在这个例子中,赋值之后,n等于1,因为它是在将m赋予n之前完成的自增操作。再看下面的代码:

  1. int n=0m=0;  
  2. n = m++; /*先将m赋于n, 之后m加1*/  
  3. cout << n << m; /*结果:0 1*/ 

这个例子中,赋值之后,n等于0,因为它是先将m赋予n,之后m再加1的。

为了更好地理解前缀操作符和后缀操作符之间的区别,可以查看这些操作的反汇编代码。即使不了解汇编语言,也可以很清楚地看到二者之间的区别,注意inc指令出现的位置:

  1. /* m=n++;的反汇编代码*/  
  2. mov ecx, [ebp-0x04] /*store n's value in ecx register*/  
  3. mov [ebp-0x08], ecx /*assign value in ecx to m*/  
  4. inc dword ptr [ebp-0x04] /*increment n*/  
  5. /*m=++n;的反汇编代码*/  
  6. inc dword ptr [ebp-0x04] /*increment n;*/  
  7. mov eax, [ebp-0x04] /*store n's value in eax register*/  
  8. mov [ebp-0x08], eax /*assign value in eax to m*/ 

从汇编代码可以看出,两者采取了相同的操作,只是顺序稍有不同而已。但是,前缀操作符的效率要优于后缀操作符,这是因为在运行操作符之前编译器需要建立一个临时的对象,而这还要从函数重载说起。

重载函数间的区别取决于它们在参数类型上

  1. ClassName & ClassName::operator++()  
  2. {  
  3.  ClassAdd (1); //increment  current object  
  4.  return *this; //return by reference the current object  
  5. }  
  6.  
  7. ClassName ClassName::operator++(int unused)  
  8. {  
  9.  ClassName temp(*this); //copy of the current object  
  10.  ClassAdd (1); //increment current object  
  11.  return temp;  //return copy  

的差异,但不论是自增的前缀还是后缀,都只有一个参数。为了解决这个语言问题,C++(www.cppentry.com)规定后缀形式有一个int类型的参数,当函数被调用时,编译器传递一个0作为int类型参数的值给该函数:

  1. //成员函数形式的重载  
  2. < Type > ClassName :: operator ++ ( ); // 前缀  
  3. < Type > ClassName :: operator ++ ( int ); // 后缀  
  4. // 非成员函数形式的重载  
  5. < Type > operator ++ (ClassName & ); // 前缀  
  6. < Type > operator ++(ClassName &,int); // 后缀 

在实现中,后缀操作会先构造一个临时对象,并将原对象保存,然后完成自增操作,最后将保存对象原值的临时对象返回。代码如下所示:

  1. ClassName & ClassName::operator++()  
  2. {  
  3.  ClassAdd (1); //increment  current object  
  4.  return *this; //return by reference the current object  
  5. }  
  6.  
  7. ClassName ClassName::operator++(int unused)  
  8. {  
  9.  ClassName temp(*this); //copy of the current object  
  10.  ClassAdd (1); //increment current object  
  11.  return temp;  //return copy  

由于前缀操作省去了临时对象的构造,因此它在效率上优于后缀操作。不过,在应用到整型和长整型的操作时,前缀和后缀操作在性能上的区别通常是可以忽略的。但对于用户自定义类型,这还是非常值得注意的。当然就像80-20规则告诉我们的那样,如果在一个很大的程序里,程序数据结构和算法不够优秀,它所能带来的效率提升也是微不足道的,不能使大局有所改变。但是既然它们有差异,我们为什么不在必要的时候采用更有效率的呢?

请记住:

对于整型和长整型的操作,前缀操作和后缀操作的性能区别通常是可以忽略的。对于用户自定义类型,优先使用前缀操作符。因为与后缀操作符相比,前缀操作符因为无须构造临时对象而更具性能优势。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇建议11:将强制转型减到最少 下一篇建议8:拒绝晦涩难懂的函数指针

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: