不知道你是否聽說過++i比i++快的說法,真的如此嗎?
這兩個表示式從我們初學程式語言的時候就會接觸到。前者是自增後取值,後者是取值後自增。
我們看乙個簡單的例子。
#include
using
namespace std;
intmain()
執行結果:
c=
0;d=
1
對於這個結果我們並不感到意外。
另外我們還注意到另外乙個有意思的現象:
#include
using
namespace std;
intmain()
編譯後報錯:
main.cpp:7:
19: error: lvalue required as unary 『&』 operand
int*c =
&(a++
);
說&作用於左值,也就是說a++的結果並非左值。但++b的結果是左值。
可簡單理解左值和右值:
在《運算子過載》一文中已經說到了運算子的過載,通過前面的例子也發現了,對於內建型別,前置自增返回物件的引用,而後置自增返回物件的原值(但非左值)。
基於上述原則,乙個前置版本和後置版本的常見實現如下:
class
test
;/*前置自增實現正規化*/
test& test::
operator++(
)/*後置自增實現正規化,為了與前置區分開,多了乙個int引數,但從來沒用過*/
const test test::
operator++(
int)
仔細觀察後,我們發現前置自增,先自增,後返回原物件的物件;沒有產生任何臨時物件;而後置自增,先儲存原物件,然後自增,最後返回該原臨時物件,那麼它就需要建立和銷毀,這樣一來,效率孰高孰低就很清楚了。
在不進行賦值的情況下,內建型別前置和後置自增的彙編都是一樣的呢!
void
test()
彙編:
push rbp
mov rbp, rsp
mov dword ptr [rbp-4]
,0add dword ptr [rbp-4]
,1noppop rbp
ret
不過,賦值的情況下,並且不開啟編譯器優化,它們的彙編**還是有差別的,有興趣的可以試試。
對於內建型別,前置和後置自增或者自減在編譯器優化的情況下,兩者並無多大差別,而對於自定義型別,如無特別需要,人們似乎更加偏愛前置自增或自減,因為後置自增常常會產生臨時物件。
但是,又能提高多少效率呢?
推薦閱讀:
什麼是運算子的過載?
for迴圈中 i和i 的區別
語法 for 語句1 語句2 語句3 語句 1 在迴圈 塊 開始前執行 語句 2 定義執行迴圈 塊 的條件 語句 3 在迴圈 塊 已被執行之後執行 這就是迴圈中的 i和i 結果一樣的原因,但是效能不一樣,稍後解釋 語句1 同上面語法中的 語句1 語句1 是可選的,也就是說不使用語句1 也可以。var...
for迴圈中 i和i 的區別
for 語句1 語句2 語句3 語句 1 在迴圈 塊 開始前執行 語句 2 定義執行迴圈 塊 的條件 語句 3 在迴圈 塊 已被執行之後執行 前者是 先引用,後增加,int i 10 system.out.println i 此時輸出的是10以上 等價與 int i 10 system.out.pr...
for迴圈中的i 與 i
今天遇到乙個for迴圈 for i 1 i 1 i 其中使用的是 i,我以為 i會先於判斷執行,就上網找了找i 與 i的區別。答案很少,有乙個說的是效率後者高一些。然後我又寫了乙個測試的 var j 0 for i 1 i 1 i,j console.log console.log i,j 發現 是...