// version 1
MyObject Widget::GetSomething() {
return MyObject();
}
これはMyObject
でコピー可能です。実行時には、標準でelisonが許可されているので、妥当な設定の "実"コンパイラを使用してコピーは作成されません。
C++ 11または14では、オブジェクトは移動可能またはコピー可能である必要があります。 Elisionは残っている。移動もコピーも行われません。
C++では、ここに移動またはコピーがありません。
いずれの場合でも、実際には戻り値にMyObject
が直接構築されます。
// version 2
MyObject Widget::GetSomething() {
return std::move(MyObject());
}
これはC++ 03では無効です。
C++ 11以降では、MyObject
が戻り値に移動されます。実行は実行時に行われなければなりません(as-ifを排除することはできません)。
// version 3
MyObject Widget::GetSomething() {
auto obj = MyObject();
return obj;
}
バージョン1と同じですが、C++ 17はC++ 11/14のように動作します。さらに、ここでの溶離はより脆弱である。一見無害な変更は、コンパイラに実際にobj
を移動させる可能性があります。
ここでは、C++ 11/14/17(およびC++ 03では2つのコピー)では理論的に2つの移動が省略されています。最初の溶離は安全で、2番目の溶離は安全です。
// version 4
MyObject Widget::GetSomething() {
auto obj = MyObject();
return std::move(obj);
}
は、実際には、これは単なるバージョン2(C++ 03でコピー)の余分な動きobj
を構築する上で発生するように振る舞うが、それは省略されているので、何も実行時に起こりません。
Elisionを使用すると、コピー/移動の副作用を排除できます。オブジェクトのライフタイムが1つのオブジェクトにマージされ、移動/コピーが削除されます。コンストラクタはまだ存在しなければならず、呼び出されることはありません。
回答
1と3の両方が同じランタイムコードにコンパイルされます。 3はやや脆弱です。
2と4の両方が同じランタイムコードにコンパイルされます。それは決して1/3より速いはずはありませんが、実行していないことを証明したコンパイラによって移動を取り除くことができれば、実行時と同じランタイムコードにコンパイルすることができます。これは保証されておらず、非常に脆弱です。
したがって1>=3>=2>=4
は、実際には速度が遅く、それ以外の速度が同じである「より脆い」コードは<=
です。あなたはif文を持っていた場合
は1よりも3が遅く作ることができる場合の例としては、:
// version 3 - modified
MyObject Widget::GetSomething() {
auto obj = MyObject();
if (err()) return MyObject("err");
return obj;
}
突然、多くのコンパイラではなくobj
をelidingの戻り値にobj
を移動することを余儀なくされ、一緒に戻り値。
「コミュニティからの広範な回答」 - 例?これはAFAIKのコンセンサスでは悪いことです。 –
あなたは私が好きなものを逃しました: 'return {}; ' –
「最大の最適化を提供する」は、本質的に実装固有の質問です –