2010-04-15 64 views
9

也許這是一個編譯器特定的事情。如果是這樣,gcc(g ++)怎麼樣?如果使用這樣的變量引用/別名:變量引用(別名)是否會導致運行時成本?

int x = 5; 
int& y = x; 
y += 10; 

它實際上需要比,如果我們沒有使用參考以上的週期。

int x = 5; 
x += 10; 

換句話說,做機器代碼的變化,還是在「別名」在編譯器級別只發生?

這可能看起來像一個愚蠢的問題,但我很好奇。特別是在可能暫時重命名某些成員變量以方便數學代碼更易於閱讀的情況下。當然,我們並不是在說這裏的瓶頸......但是這是我正在做的事情,所以我只是想知道是否存在「實際」差異......或者只是表面上的差異。

回答

9

它可以被視爲別名,但不是效率。在引擎蓋下面,引用是一個具有更好語法和更高安全保證的指針。因此,你有一個「取消引用」操作運行時懲罰。除非編譯器優化它,但我不會指望通常。

在編譯器是否優化它的問題的情況下,除了查看生成的程序集外沒有別的辦法。

+0

很好的答案。謝謝 – cheshirekow 2010-04-15 00:30:21

+4

答案並不完全準確。引用背後的意圖之一是實現別名的概念,即現有對象的替代名稱。我相信這是在TC++ PL中明確陳述的。儘管情況並非總是如此,但「別名」仍然是許多情況下參考文獻的準確描述。 – AnT 2010-04-15 00:32:20

+0

@AndreyT,我從來沒有聽說過引用是別名的想法,你能否在這裏標明標準的段落? – 2010-04-15 00:35:08

4

確切知道的唯一方法是編譯它並檢查編譯器的輸出。通常,引用的開銷類似於指針的開銷,因爲指針通常是如何實現引用的。然而,鑑於你正在展示的簡單案例,我相信這個參考將被優化掉。

+0

是的,我可能有一天會做一些簡單的測試,看看它是否被優化出來......現在,它不是太重要。 – cheshirekow 2010-04-15 00:31:35

0

是的,取消引用後面的指針引起額外的運行時成本,但可能不重要。以任何最清晰的方式編寫代碼,並最乾淨地表達您所瞄準的語義,然後在性能問題時運行在分析器中(瓶頸幾乎不是您猜測的)。如果你在MacOS上,Shark是太棒了。

+0

完成。就像我說的,只是好奇。在Mac上開發? ew ...;) – cheshirekow 2010-04-15 00:32:21

+0

不要怠慢你不知道的東西! :-)調試和分析工具是一流的,不需要$$$。 – metasim 2010-04-15 01:34:57

+0

這個答案是錯誤的。 – 2015-11-25 18:34:25

4

的確,在大多數情況下,引用實現了「別名」的概念,這是他們綁定對象的替代名稱。

但是,通常情況下引用是通過指針實現的。儘管如此,一個好的編譯器只會在實際綁定在運行時確定的情況下使用實際指針來實現引用。如果在編譯時已知綁定(和類型匹配),編譯器通常將引用作爲同一對象的替代名稱,在這種情況下,通過引用訪問對象不會有性能損失(與訪問相比它通過它的原名)。

你的例子就是其中的一種,當你不應該引用性能損失時。

4

這兩個函數都編譯成g++中的完全相同的代碼,即使只是使用-O1。 (我添加了return聲明以確保計算沒有完全消除。)

沒有指針,只有一個引用。在這個微不足道的例子中,沒有性能差異。儘管如此,這並不能保證對於所有參考用途來說,情況總是如此(沒有性能差異)。

int f() 
{ 
    int x = 5; 
    x += 10; 
    return x; 
} 

int f() 
{ 
    int x = 5; 
    int & y = x; 
    y += 10; 
    return y; 
} 

彙編:

movl $15, %eax 
ret 
+1

不確定這是一個公平的測試,因爲如您的結果所示,函數的整個主體可以在編譯時進行評估。 – 2010-04-15 00:52:14

+1

@Daniel Pryden:但這是被問到的代碼。你能提出一個更公平的測試代碼嗎? – 2010-04-15 01:01:15

+0

我認爲我的測試更公平一些,因爲編譯器在編譯時沒有評估主體。 (但我沒有測試相同的代碼)。 – 2015-07-17 15:27:42

2

我比較2層的程序在GNU/Linux。下面僅顯示GCC輸出,但是叮聲結果導致相同的結論。

GCC版本:4.9.2

鏘版本:3.4.2

的程序

1.cpp

#include <stdio.h> 
int main() 
{ 
    int x = 3; 
    printf("%d\n", x); 
    return 0; 
} 

2.cpp

#include <stdio.h> 
int main() 
{ 
    int x = 3; 
    int & y = x; 
    printf("%d\n", y); 
    return 0; 
} 

測試

嘗試1:無優化

gcc -S --std=c++11 1.cpp

gcc -S --std=c++11 2.cpp

1.cpp的所得的組件是短。

嘗試2:

gcc -S -O2 --std=c++11 1.cpp

gcc -S -O2 --std=c++11 2.cpp

所得到的組件是優化完全相同。

的組件輸出

1.cpp,沒有優化

.file "1.cpp" 
    .section .rodata 
.LC0: 
    .string "%d\n" 
    .text 
    .globl main 
    .type main, @function 
main: 
.LFB0: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    subq $16, %rsp 
    movl $3, -4(%rbp) 
    movl -4(%rbp), %eax 
    movl %eax, %esi 
    movl $.LC0, %edi 
    movl $0, %eax 
    call printf 
    movl $0, %eax 
    leave 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE0: 
    .size main, .-main 
    .ident "GCC: (Debian 4.9.2-10) 4.9.2" 
    .section .note.GNU-stack,"",@progbits 

2.cpp,沒有優化

.file "2.cpp" 
    .section .rodata 
.LC0: 
    .string "%d\n" 
    .text 
    .globl main 
    .type main, @function 
main: 
.LFB0: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    subq $16, %rsp 
    movl $3, -12(%rbp) 
    leaq -12(%rbp), %rax 
    movq %rax, -8(%rbp) 
    movq -8(%rbp), %rax 
    movl (%rax), %eax 
    movl %eax, %esi 
    movl $.LC0, %edi 
    movl $0, %eax 
    call printf 
    movl $0, %eax 
    leave 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE0: 
    .size main, .-main 
    .ident "GCC: (Debian 4.9.2-10) 4.9.2" 
    .section .note.GNU-stack,"",@progbits 

1.cpp,具有優化

.file "1.cpp" 
    .section .rodata.str1.1,"aMS",@progbits,1 
.LC0: 
    .string "%d\n" 
    .section .text.unlikely,"ax",@progbits 
.LCOLDB1: 
    .section .text.startup,"ax",@progbits 
.LHOTB1: 
    .p2align 4,,15 
    .globl main 
    .type main, @function 
main: 
.LFB12: 
    .cfi_startproc 
    subq $8, %rsp 
    .cfi_def_cfa_offset 16 
    movl $3, %esi 
    movl $.LC0, %edi 
    xorl %eax, %eax 
    call printf 
    xorl %eax, %eax 
    addq $8, %rsp 
    .cfi_def_cfa_offset 8 
    ret 
    .cfi_endproc 
.LFE12: 
    .size main, .-main 
    .section .text.unlikely 
.LCOLDE1: 
    .section .text.startup 
.LHOTE1: 
    .ident "GCC: (Debian 4.9.2-10) 4.9.2" 
    .section .note.GNU-stack,"",@progbits 

2。CPP,與優化

.file "1.cpp" 
    .section .rodata.str1.1,"aMS",@progbits,1 
.LC0: 
    .string "%d\n" 
    .section .text.unlikely,"ax",@progbits 
.LCOLDB1: 
    .section .text.startup,"ax",@progbits 
.LHOTB1: 
    .p2align 4,,15 
    .globl main 
    .type main, @function 
main: 
.LFB12: 
    .cfi_startproc 
    subq $8, %rsp 
    .cfi_def_cfa_offset 16 
    movl $3, %esi 
    movl $.LC0, %edi 
    xorl %eax, %eax 
    call printf 
    xorl %eax, %eax 
    addq $8, %rsp 
    .cfi_def_cfa_offset 8 
    ret 
    .cfi_endproc 
.LFE12: 
    .size main, .-main 
    .section .text.unlikely 
.LCOLDE1: 
    .section .text.startup 
.LHOTE1: 
    .ident "GCC: (Debian 4.9.2-10) 4.9.2" 
    .section .note.GNU-stack,"",@progbits 

結論

沒有運行成本,當談到優化GCC輸出。與clang一樣(在版本3.4.2中測試):優化開始時,生成的彙編代碼在兩個程序中都是相同的。

相關問題