2017-08-04 23 views
1

我每次迴路通過一類,這是我通過指針訪問一個數組裏面,我問自己,這同一個問題:性能:指針引用在C++

是否每個迭代由指針的解引用開銷產生?解除引用鏈加起來嗎? 例如:

ClassA *a = new ClassA(); 
ClassB *b = new ClassB(); 

for(int i = 0; i < 10; i++){ 

    a->b->array[i].foo(); 

} 

如果我猜的話,我會說這涉及20提領步,每一個三分球,10次迭代。 但我可以想象,它減少到10,因爲鏈接的指針被編譯器翻譯爲單個指針。我甚至可以想象,由於一些緩存 - 巫術或其他東西,它減少到1。

有人可以告訴,也許向我解釋,這是如何表現明智?會真的很感激它!

順便說一句,我知道這種類似的問題已經在這裏得到解答,但我無法推斷出這個特定主題的答案。所以請不要責怪我再次提出這個話題。

+0

是B的一員嗎? ClassB的全局作用域b實例與未知對象b(它是A的成員)有什麼關係? – franji1

+0

「*如果我不得不猜測,我會說這涉及20個解除引導步驟*」 - 30,實際上。 ''a->','b->'和'array [i]'都是指針解引用,所以每循環迭代有3次解引用,10次迭代。 –

回答

3

這真的取決於編譯器(特別是優化器)如何生成代碼。在as-if rule下,只要用戶無法區分程序在外部的行爲差異,編譯器就可以做任何想做的事情,現代編譯器可以非常聰明地應用它們的優化。

實際上,我認爲最現代的優化器只有在無法知道foo()內發生了什麼時才能優化循環 - 特別是,如果它們不能保證foo()的實現將不會更改ab的值,那麼他們將被迫生成代碼,對每個循環迭代執行單獨的取消引用ab,只是爲了確保即使ab的值發生了正確的事情更改。

你可以自己找到如果你不介意閱讀一些彙編代碼會發生什麼 - 只需編譯程序進行彙編,啓用優化(例如g++ -O3 -S mytest.cpp)並讀取得到的mytest.S文件以查看編譯器做了什麼。嘗試使用在同一文件中實現的foo()(以便編譯器可以明確地看到foo()的內容),並將foo實現在不同的文件中(以便編譯器可能必須將foo()視爲「黑色盒子「),看看有什麼不同。

+0

非常感謝,我甚至沒有考慮到foo()可能會改變其中一個指針的事實,但是當猜測編譯器會做什麼時,這實際上是一個非常有趣的事情。我不得不承認,我以前從來沒有閱讀過單行程序集,但我想如果我對優化感興趣,現在是開始的好時機:D – user3808217

2

您可一定要通過做這樣的事情擺脫一些反引用:

// create a pointer to the b class outside of the loop 
ClassB * bptr = a->b;   

// use the pointer inside the loop 
for(int i = 0; i < 10; i++){ 

    bptr->array[i].foo(); 

} 
+0

並且在輸入之前保存一個指向'array'的指針循環,並使循環增量指針在每次迭代,而不是使用索引運算符。曾經的30個解除引用減少到10個,而不像你的例子那樣是20個。 –

1

我希望1次內存訪問,因爲和A-> B不循環內改變,因此沒有必要再次獲取它們。我也知道所有的值爲a-> b-> array [i],所以它可以被預取。