2015-12-27 39 views
2

箭頭解引用p->m(*p).m的語法糖,它看起來像它可能涉及兩個單獨的內存查找操作 - 一個找到堆上的對象,第二個找到成員字段偏移。C++重複箭頭操作符解引用性能vs點運算符

這讓我質疑這兩個代碼片段之間是否存在任何性能差異。假設classA具有30+需要被以各種順序訪問(不一定連續或連續地)的各種類型的不同字段:1

版本:

void func(classA* ptr) 
{ 
    std::string s = ptr->field1; 
    int i = ptr->field2; 
    float f = ptr->field3; 
    // etc... 
} 

2版本:

void func(classA* ptr) 
{ 
    classA &a = *ptr; 
    std::string s = a.field1; 
    int i = a.field2; 
    float f = a.field3; 
    // etc... 
} 

所以我的問題是這兩個版本之間是否存在性能差異(即使非常小),或者如果編譯器是s (即使不同的字段訪問被它們之間的許多其他代碼行中斷,我沒有在這裏顯示)。

+1

如果沒有人知道答案,我將不得不微調自己的基準。不過,我希望將來可以爲其他人提供答案。 –

+0

測量它...或者比較程序集的輸出,你甚至可以在線完成https://gcc.godbolt.org/ – StoryTeller

+0

好吧,只要你自己找到答案就可以了您的代碼或使用分析器。 – johnbakers

回答

2

箭頭解除引用對 - >米爲(* P).M

即通常不是真的,但是在有限的上下文中,你所要求真實語法糖。一個上找到堆和第二到接着 定位構件字段偏置對象 -

出現像它可能涉及兩個獨立的存儲器查找 操作

根本不是。它是一個讀取持有指針的參數或局部變量,另一個讀取成員。但是任何合理的優化器都會將指針保留在您顯示的代碼中的寄存器中,因此無需額外訪問。

但您的替代版本也有一個本地指針,所以沒有差別反正(在方向上至少你問):

classA &a = *ptr; 

假設整體功能沒有被內聯或承擔一些其他原因編譯器不知道到底哪裏ptr分,&必須爲指針,因此無論是編譯器可以推斷它是安全的a是的*ptr別名所以NO差,或編譯器必須做a別名*copy_of_ptr所以ver sion使用&會比複製ptr的成本慢(不像預期的那樣快)。

即使不同領域的訪問是通過它們之間的其他 多行代碼,這是我沒有在這裏顯示

那你移動朝有趣的案例中斷。如果該干預代碼可能會改變ptr那麼顯然這兩個版本的行爲不同。但是如果人類可以看到介入代碼不能更改ptr,而編譯器無法看到:那麼這兩個版本在語義上是相等的,但編譯器不知道,編譯器可能會生成較慢您嘗試通過創建參考進行手動優化版本的代碼。

+0

謝謝,你的回答是有道理的。我猜我的心理呃逆沒有意識到*版本2 *仍然需要與*版本1 *完全相同的指針查找。你是正確的,在最好的情況下,*版本2 *將「速度」*版本1 *,在最壞的情況下,它可能會稍微慢一點。 –

2

大多數(?all)編譯器在引擎下實現引用作爲指針,所以我期望在生成的程序集中沒有區別(除了可能的副本來初始化引用 - 但我希望優化器消除即使這樣) 。

一般來說,這種微型優化是不值得的。總是傾向於專注於清晰和正確的代碼。這是當然不值得這種優化,直到你測量了瓶頸在哪裏。

+1

大多數編譯器在引擎蓋下實現**引用的困難**使用。引用的簡單使用是作爲編譯時間別名來實現的。 'int &a=x;''a'在編譯時可能只是'x'的另一個名字。 'a'可能不需要它自己的任何實現。 – JSF

+0

Ish。指針也是如此。 'int * p =&x;''* p'在編譯時可能只是'x'的另一個名字,'p'可能不需要它自己的任何實現。 –