2016-03-24 31 views
1

我正在分析按函數返回的值。見下面的實際問題:從gcc 5.3 -O0 -fno-elide-constructors on godbolt返回值兩份

struct S{ int a, b, c, d; }; 
S f(){ 
S s; 
s.b=5; 
return s; 
} 

int main(){ 
    S s= f(); 
    s.a =2; 
} 

編譯器輸出:

f(): 
     pushq %rbp 
     movq %rsp, %rbp 
     subq $32, %rsp 
     movl $5, -28(%rbp) 
     leaq -32(%rbp), %rdx 
     leaq -16(%rbp), %rax 
     movq %rdx, %rsi 
     movq %rax, %rdi 
     call S::S(S const&) 
     movq -16(%rbp), %rax 
     movq -8(%rbp), %rdx 
     leave 
     ret 
main: 
     pushq %rbp 
     movq %rsp, %rbp 
     subq $32, %rsp 
     call f() 
     movq %rax, -16(%rbp) 
     movq %rdx, -8(%rbp) 
     leaq -16(%rbp), %rdx 
     leaq -32(%rbp), %rax 
     movq %rdx, %rsi 
     movq %rax, %rdi 
     call S::S(S const&) 
     movl $2, -32(%rbp) 
     movl $0, %eax 
     leave 
     ret 

什麼是我的問題嗎?

  1. 爲什麼有稱爲兩個拷貝構造函數?我不明白爲什麼它是必要的。
+8

Nononono,代碼比鏈接更好。順便說一下,這個鏈接看起來像_crazy_並且被格式化爲代碼,所以沒有人可能會訪問它 – ForceBru

+0

如果你不想在這裏發佈完整的代碼,那很好。但至少發佈了一個最小版本,其中包含您描述的問題 – BrainStone

+0

並不真正有興趣點擊粗略鏈接。 – djechlin

回答

2

f()內部的複製構造函數被調用,因爲使用了對象的「返回」。這會提示它將其副本創建爲一個臨時變量,然後傳遞給main。複製構造函數主要是明顯的f()返回一個S對象,它被複制到「s

2

構造函數的兩次之一被調用來構建一個用作返回值f()的臨時對象。如果你想避免這種額外的開銷,你必須依靠C++11 move constructors

+0

當建立臨時對象(請給我線數) – Gilgamesz

+0

@Gilgamesz:在這種情況下,你應該編譯任何優化級別(甚至是用於調試的最小'-Og'優化,'f()'將編譯爲'movabsq $ 21474836480,%rax' /'movl $ 0 ,%edx' /'ret'。'main()'當然會完全優化。) –