转:前置自增(自减)和后置自增(自减)

第一篇:转自 http://pppboy.blog.163.com/blog/static/30203796201041014447359/

                  http://pppboy.blog.163.com/blog/static/302037962011112311822421/

一、基本认识

前置递增效率更高,后置式递增要拷贝一个临时对象。

1 int b = i++; 
2 //可以分解为一下过程:  
3 int temp = i;  
4 b = temp;  
5 i = i + 1;

n++要开辟一个变量来保存n的值并返回,然后让n这个变量中的值加 1。而++n直接把1加到n这个变量的空间中去,并返回n这个空间中的值,没有开辟任何临时空间,性能更高。

 

n+=1与n=n+1在结果上是等价的。但使用复合赋值操作符+=时,直接把1加到变量n的空间中去,左操作数只计算了一次加法;而使用长表达式 n=n+1时,先要去n这个变量空间中去取值(要寻址),与1做一次加法计算,然后做一次赋值计算把结果存入到n这个空间中,这样左操作数n计算了两次。因此,n+=1的性能更高。事实上,这也是复合赋值操作符存在一个基本原因。很多人刚开始八成会困惑,为什么会存在+=,-=,*=这样的操作符,能提高程序的性能就是其中的一个原因。

 

1.VC编译器优化?能前置,就别后置。(这一条应该视情形而定)

2.养成使用前置操作符的习惯

3.养成使用复合赋值操作符的习惯

 

二、重载和句法区别

C++规定后缀形式有一个int类型参数,当函数被调用时,编译器传递一个0做为int参数的值给该函数。

一个例子可以说明一切

 1  #include "stdafx.h" 
 2  #include <iostream> 
 3   
 4  class NumUpper 
 5  { 
 6  public: 
 7    
 8    //前缀,返回引用 
 9     NumUpper& operator++() 
10     { 
11       std::cout << "++ prefix\n"; 
12    
13       *this += 1; //operator+= 
14       return *this; 
15     } 
16    
17     //后缀 返回const对象,int参数 
18     const NumUpper operator++(int)  
19     { 
20       std::cout << "postfix ++ \n"; 
21    
22       NumUpper preNum = *this; 
23       ++(*this); 
24       return preNum; 
25     } 
26    
27      NumUpper& operator+=(int num) 
28      { 
29        mNum += num; 
30        return *this; 
31      } 
32    
33   private: 
34     int mNum; 
35   }; 
36    
37   //main 
38   int main(int argc, char* argv[]) 
39   { 
40    
41     NumUpper upper; 
42    
43     //前置 
44     std::cout << "-----------------------\n"; 
45     ++upper; 
46    
47     //后置 
48     std::cout << "-----------------------\n"; 
49     upper++; 
50    
51     //前置 
52     std::cout << "-----------------------\n"; 
53     upper.operator++(); 
54      
55     //后置 
56     std::cout << "-----------------------\n"; 
57     upper.operator++(0); 
58    
59     std::cout << "-----------------------\n"; 
60     system("pause"); 
61     return 0; 
62   } 
63   

//output:

----------------------- 
++ prefix 
----------------------- 
postfix ++ 
++ prefix 
----------------------- 
++ prefix 
----------------------- 
postfix ++ 
++ prefix 
----------------------- 
请按任意键继续. . .

从上面的例子可以看到:

前缀形式返回一个引用

后缀形式返回一个const类型对象

 

三、其它联想

1.const的使用

比如不能用 upper++++这样,因为返回的是const,正好这个const就是为了防止这么连加用的。

2.对自减也是一样

3.还是效率问题

(1)如编程规范所说,不要进行不成熟的劣化:

<1>在使用前置++操作很合适的场合,却偏偏使用了后置++

<2>可以传引用的时候,去偏偏用了传值

<3> 构造函数中可以使用初始化列表,却偏偏使用赋值

(2)大气使用,该用后置的时候还是要用后置,正确远比高效重要

 

四、引用参考:

《More Effective C++》

C++ Standard Library

 

第二篇:转自 http://www.cnblogs.com/maxwellp/archive/2012/02/11/2346844.html

 

《C++ Primer》确实给我带来了很多惊喜。

作为一本专业的具有较高门槛的"入门书",它有很多地方实在是国内的书不可及的,这不仅在于内容上的严谨,更表现在优秀的习题所带给学习者的启迪。

 

习题5.16

你认为为什么C++不叫做++C?

 

看到这个习题,顿感眼前一亮(不禁想起某些国内书籍的题目,真是平淡如水),这对于理解前自增操作与后自增操作而言着实是个好的题目。

想弄明白这个问题,就需要先理解一些基础的概念。什么是自增操作呢?

 

++操作符,即自增操作符。自增操作符有两种形式:前置操作和后置操作。前自增操作生成左值,在给操作数加1后返回改变后的操作数值。后自增操作生成右值,给操作数加1但返回未改变的操作数原值。

*事实上,因为C++具有操作符重载的功能,自增操作不仅仅可以表示加1

 

前置操作返回的是加1后的值,返回的是对象本身,所以这是左值。

后置操作返回的是加1前的值,其返回值可以近似的理解为与原操作数值相等的常量,所以是一个右值。

 

具体例子:

 

int i = 0, j;
j = ++i; // j = 1 , i = 1:prefix yields incremented value
j = i++; // j = 1 , i = 2:postfix yields unincremented value

 

附左值与右值的概念:

 

左值:可以出现在赋值操作左边的值。非const左值可读可写。

右值:可用于赋值操作的右边但不能用于左边的值。右值只能读不能写。

 

左值可以出现在赋值操作右端,但右值不可以出现在赋值操作左端,将后自增操作置于赋值操作左端将会出现编译错误。

另外需要注意:

 

由于后置操作符要返回未加1前的值作为操作的结果,所以必须要保存操作数原来的值(即上一篇说的临时对象),对于比较复杂的类型,这种额外工作可能会花费更大的代价。

建议:只有在必要时才使用后置操作符。

 

最后,让我们用全新的角度去审视C++的命名原因

 

C++之名是Rick Mascitti在1983年夏天定名的(参见The C++ Programming Language(Special Edition)1.4节),C说明它本质上是从C语言演化而来的,“++”是C语言的自增操作符。C++语言是C语言的超集,是在C语言基础上进行的扩展(引入了new、delete等C语言中没有的操作符,增加了面向对象程序设计的直接支持,等等),是先有C语言,再进行++。根据自增操作符前、后置形式的差别,C++表示对C语言进行扩展之后,还可以使用C语言的内容;而写成++C则表示无法再使用C的原始值了,也就是说C++不能向下兼容C了,这与实际情况不符。 

 

如果以后有人问你这个问题,你会回答了吗?囧。

 

posted @ 2014-02-14 20:54  kira2will  阅读(2457)  评论(0编辑  收藏  举报