這兩個vector
的暗示副本都可以 - 而且經常被 - 刪除。指定的返回值優化可以消除返回語句return out;
中隱含的副本,並且可以消除oof
副本初始化中隱含的臨時副本。
在這兩種優化中,在vector<foo> out;
中構造的對象與oof
的對象相同。
用這樣的仿真測試用例來測試這些優化中的哪一個正在執行更容易。
struct CopyMe
{
CopyMe();
CopyMe(const CopyMe& x);
CopyMe& operator=(const CopyMe& x);
char data[1024]; // give it some bulk
};
void Mutate(CopyMe&);
CopyMe fn()
{
CopyMe x;
Mutate(x);
return x;
}
int main()
{
CopyMe y = fn();
return 0;
}
複製構造函數是聲明的但未定義的,以便對它的調用不能被內聯和消除。用現在比較老的gcc 4.4編譯,在處給出以下程序集(經過濾除C++名稱並編輯刪除非代碼)。
fn():
pushq %rbx
movq %rdi, %rbx
call CopyMe::CopyMe()
movq %rbx, %rdi
call Mutate(CopyMe&)
movq %rbx, %rax
popq %rbx
ret
main:
subq $1032, %rsp
movq %rsp, %rdi
call fn()
xorl %eax, %eax
addq $1032, %rsp
ret
可以看出,沒有對拷貝構造函數的調用。事實上,即使在-O0
,gcc也會執行這些優化。您必須提供-fno-elide-constructors
以關閉此行爲;如果你這樣做,那麼gcc會生成兩個對CopyMe
的拷貝構造函數的調用 - 一個在fn()
的調用內部和一個外部。
fn():
movq %rbx, -16(%rsp)
movq %rbp, -8(%rsp)
subq $1048, %rsp
movq %rdi, %rbx
movq %rsp, %rdi
call CopyMe::CopyMe()
movq %rsp, %rdi
call Mutate(CopyMe&)
movq %rsp, %rsi
movq %rbx, %rdi
call CopyMe::CopyMe(CopyMe const&)
movq %rbx, %rax
movq 1040(%rsp), %rbp
movq 1032(%rsp), %rbx
addq $1048, %rsp
ret
main:
pushq %rbx
subq $2048, %rsp
movq %rsp, %rdi
call fn()
leaq 1024(%rsp), %rdi
movq %rsp, %rsi
call CopyMe::CopyMe(CopyMe const&)
xorl %eax, %eax
addq $2048, %rsp
popq %rbx
ret
它可以被忽略。但是,請注意,標準_still_要求複製構造函數可訪問(例如非私有的) – sehe 2011-05-26 13:28:17