缶の暗黙のコピーは両方ともvector
(そして多くの場合は削除されます)削除されます。名前付き戻り値の最適化により、returnステートメントに含まれるコピーを削除できます。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;
}
コピーコンストラクターは宣言されていますが、定義されていないため、コピーコンストラクターへの呼び出しをインライン化して削除することはできません。現在比較的古いgcc4.4でコンパイルすると、で次のアセンブリが得られます-O3 -fno-inline
(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
ご覧のとおり、コピーコンストラクターの呼び出しはありません。実際、gccはでさえこれらの最適化を実行し-O0
ます。-fno-elide-constructors
この動作をオフにするには、を指定する必要があります。これを行うと、gccはのコピーコンストラクターへの2つの呼び出しを生成します。1つはへの呼び出しの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