我希望,因爲編譯器(至少在這種情況下)可以內聯的所有相關代碼在std::vector
,這將是相同的代碼[除了1000是機器碼中真正的常量字面量,並且Bodies.size()
將是一個「可變」值]。
發現的簡短摘要:
編譯器不要求每次迭代的載體size()
功能,它計算的是,在循環的開始,並使用它作爲一個「常數值」。
循環中的實際代碼是相同的,只有循環的準備是不同的。
一如既往:如果性能非常重要,請使用數據和編譯器測量系統。否則,寫最有意義爲您設計的代碼(我更喜歡使用for(auto i : vec)
,因爲這是簡單,直接的[並適用於所有的容器])
佐證:
取咖啡後,我寫了這個代碼:
class X
{
public:
void Update() { x++; }
operator int() { return x; }
private:
int x = rand();
};
extern std::vector<X*> vec;
const size_t vec_size = 1000;
void Process1()
{
for(auto i : vec)
{
i->Update();
}
}
void Process2()
{
for(size_t i = 0; i < vec.size(); i++)
{
vec[i]->Update();
}
}
void Process3()
{
for(size_t i = 0; i < vec_size; i++)
{
vec[i]->Update();
}
}
(帶main
功能,填補了陣列一起,並調用處理1(),進程2()和Process3() - 該main
是在一個單獨的文件,以避免編譯器決定內聯的一切,使得它很難說什麼是什麼)
這裏是由g ++ 4.9.2生成的代碼:
0000000000401940 <_Z8Process1v>:
401940: 48 8b 0d a1 18 20 00 mov 0x2018a1(%rip),%rcx # 6031e8 <vec+0x8>
401947: 48 8b 05 92 18 20 00 mov 0x201892(%rip),%rax # 6031e0 <vec>
40194e: 48 39 c1 cmp %rax,%rcx
401951: 74 14 je 401967 <_Z8Process1v+0x27>
401953: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
401958: 48 8b 10 mov (%rax),%rdx
40195b: 48 83 c0 08 add $0x8,%rax
40195f: 83 02 01 addl $0x1,(%rdx)
401962: 48 39 c1 cmp %rax,%rcx
401965: 75 f1 jne 401958 <_Z8Process1v+0x18>
401967: f3 c3 repz retq
0000000000401970 <_Z8Process2v>:
401970: 48 8b 35 69 18 20 00 mov 0x201869(%rip),%rsi # 6031e0 <vec>
401977: 48 8b 0d 6a 18 20 00 mov 0x20186a(%rip),%rcx # 6031e8 <vec+0x8>
40197e: 31 c0 xor %eax,%eax
401980: 48 29 f1 sub %rsi,%rcx
401983: 48 c1 f9 03 sar $0x3,%rcx
401987: 48 85 c9 test %rcx,%rcx
40198a: 74 14 je 4019a0 <_Z8Process2v+0x30>
40198c: 0f 1f 40 00 nopl 0x0(%rax)
401990: 48 8b 14 c6 mov (%rsi,%rax,8),%rdx
401994: 48 83 c0 01 add $0x1,%rax
401998: 83 02 01 addl $0x1,(%rdx)
40199b: 48 39 c8 cmp %rcx,%rax
40199e: 75 f0 jne 401990 <_Z8Process2v+0x20>
4019a0: f3 c3 repz retq
00000000004019b0 <_Z8Process3v>:
4019b0: 48 8b 05 29 18 20 00 mov 0x201829(%rip),%rax # 6031e0 <vec>
4019b7: 48 8d 88 40 1f 00 00 lea 0x1f40(%rax),%rcx
4019be: 66 90 xchg %ax,%ax
4019c0: 48 8b 10 mov (%rax),%rdx
4019c3: 48 83 c0 08 add $0x8,%rax
4019c7: 83 02 01 addl $0x1,(%rdx)
4019ca: 48 39 c8 cmp %rcx,%rax
4019cd: 75 f1 jne 4019c0 <_Z8Process3v+0x10>
4019cf: f3 c3 repz retq
雖然彙編代碼如下對於這些情況中的每一個都略有不同,實際上,我會說你會很難推測這些循環之間的差異,事實上,在代碼上運行perf
表明它是「所有循環的同一時間「[這是100000個元素和100個調用Process1,Process2和Process3的一個循環,否則時間主要爲main
中的new X
]:
31.29% a.out a.out [.] Process1
31.28% a.out a.out [.] Process3
31.13% a.out a.out [.] Process2
除非你認爲1/10的百分比是顯著 - 這可能是東西,需要一個星期來運行,但是這只是一秒鐘[我的機器上0.163秒]零點幾,和可能比其他任何測量誤差更大 - 實際上理論上最短的時間應該是最慢的,Process2,使用vec.size()
。我以更高的循環數進行了另一次運行,現在每個循環的測量值相互之間爲0.01% - 換言之,花費的時間相同。當然,如果你仔細觀察,你會發現除了Process3
的早期部分外,所有三種變體的實際循環內容基本相同,因爲編譯器知道我們將至少執行一個循環 - Process1
和Process2
必須在第一次迭代之前檢查「是空載體」。這對於很短的向量長度會有所不同。
_ _'Bodies.size( )'當然。 –