「コピーの省略」の版間の差分
Semi-Brace (会話 | 投稿記録) m編集の要約なし |
|||
11行目: | 11行目: | ||
</ref> なお、参照に束縛されている一時オブジェクトは最適化されない。例: |
</ref> なお、参照に束縛されている一時オブジェクトは最適化されない。例: |
||
< |
<syntaxhighlight lang="cpp"> |
||
#include <iostream> |
#include <iostream> |
||
int n = 0; |
int n = 0; |
||
26行目: | 26行目: | ||
return 0; |
return 0; |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
言語標準によると、[[例外処理|例外]]として投げられるオブジェクトにも、同じような最適化が適用される。<ref name="C++03 15.1/5">[[International Organization for Standardization|ISO]]/[[International Electrotechnical Commission|IEC]] (2003). ''[[ISO/IEC 14882|ISO/IEC 14882:2003(E): Programming Languages - C++]] ツァ15.1 Throwing an exception [except.throw]'' para. 5</ref><ref name="C++03 15.3/17">[[International Organization for Standardization|ISO]]/[[International Electrotechnical Commission|IEC]] (2003). ''[[ISO/IEC 14882|ISO/IEC 14882:2003(E): Programming Languages - C++]] ツァ15.3 Handling an exception [except.handle]'' para. 17</ref> しかし、投げられたオブジェクトから''例外オブジェクト''へのコピー、そして''例外オブジェクト''から''例外宣言''の''catch節''へのコピーのどちらも、最適化されるかもしれないし、されないかもしれない。これは、[[一時オブジェクト]]でも、名前付きオブジェクトでも同様である。<ref name="DR 479">{{cite web|url=http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#479|title=C++ Standard Core Language Defect Reports|publisher=WG21|accessdate=2009-03-27}}</ref> 例: |
言語標準によると、[[例外処理|例外]]として投げられるオブジェクトにも、同じような最適化が適用される。<ref name="C++03 15.1/5">[[International Organization for Standardization|ISO]]/[[International Electrotechnical Commission|IEC]] (2003). ''[[ISO/IEC 14882|ISO/IEC 14882:2003(E): Programming Languages - C++]] ツァ15.1 Throwing an exception [except.throw]'' para. 5</ref><ref name="C++03 15.3/17">[[International Organization for Standardization|ISO]]/[[International Electrotechnical Commission|IEC]] (2003). ''[[ISO/IEC 14882|ISO/IEC 14882:2003(E): Programming Languages - C++]] ツァ15.3 Handling an exception [except.handle]'' para. 17</ref> しかし、投げられたオブジェクトから''例外オブジェクト''へのコピー、そして''例外オブジェクト''から''例外宣言''の''catch節''へのコピーのどちらも、最適化されるかもしれないし、されないかもしれない。これは、[[一時オブジェクト]]でも、名前付きオブジェクトでも同様である。<ref name="DR 479">{{cite web|url=http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#479|title=C++ Standard Core Language Defect Reports|publisher=WG21|accessdate=2009-03-27}}</ref> 例: |
||
< |
<syntaxhighlight lang="cpp"> |
||
#include <iostream> |
#include <iostream> |
||
50行目: | 50行目: | ||
} // このコピーも省略されるかどうかは不確かである。 |
} // このコピーも省略されるかどうかは不確かである。 |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
言語標準に準拠した[[コンパイラ]]は、上記のコードから"Hello World!"と二度出力する[[プログラム (コンピュータ)|プログラム]]を生成しなければならなかった。[[C++11]]では、名前付きオブジェクトの例外オブジェクトへのコピーと、例外ハンドラで宣言されたオブジェクトへのコピーを省略することを本質的に許した<ref name="DR 479">{{cite web|url=http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#479|title=C++ Standard Core Language Defect Reports|publisher=WG21|accessdate=2009-03-27}}</ref>ことで、その問題は対処された。 |
言語標準に準拠した[[コンパイラ]]は、上記のコードから"Hello World!"と二度出力する[[プログラム (コンピュータ)|プログラム]]を生成しなければならなかった。[[C++11]]では、名前付きオブジェクトの例外オブジェクトへのコピーと、例外ハンドラで宣言されたオブジェクトへのコピーを省略することを本質的に許した<ref name="DR 479">{{cite web|url=http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#479|title=C++ Standard Core Language Defect Reports|publisher=WG21|accessdate=2009-03-27}}</ref>ことで、その問題は対処された。 |
2020年7月5日 (日) 23:06時点における版
C++プログラミングにおけるコピーの省略(コピーのしょうりゃく)とは、不必要なオブジェクトのコピーを除去するコンパイラ最適化技術のことである。C++言語標準は基本的に、出来上がったプログラムの表面上の動作が言語標準が義務付けた通りであれば、実装はどのような最適化を施しても良いとしている。(as-ifルール)
しかし、プログラムの動作が変更され得るにも関わらず、それでもコピーが省略されうる状況を言語標準は幾つか挙げている。その中で最も有名なのが戻り値最適化であり、もう一つは、クラス型の一時オブジェクトが、同じ型のオブジェクトへとコピーされるときの最適化である。これも広く実装されており、C++言語標準で挙げられている。[1] 結果的に、コピー初期化と直接初期化の間にパフォーマンス上の違いはないが、セマンティクス上ではそうではなく、コピー初期化にはアクセス可能なコピーコンストラクタが未だに必要である。[2] なお、参照に束縛されている一時オブジェクトは最適化されない。例:
#include <iostream>
int n = 0;
struct C {
explicit C(int) {}
C(const C&) { ++n; } // 目に見える副作用を持つコピーコンストラクタ
}; // 静的な記憶時間を持つオブジェクトを書き換える
int main() {
C c1(42); // 直接初期化。 C::C(42) を呼ぶ
C c2 = C(42); // コピー初期化。 C::C( C(42) ) を呼ぶ
std::cout << n << std::endl; // コピーが省略されたなら 0 、そうでなければ 1 を出力する
return 0;
}
言語標準によると、例外として投げられるオブジェクトにも、同じような最適化が適用される。[3][4] しかし、投げられたオブジェクトから例外オブジェクトへのコピー、そして例外オブジェクトから例外宣言のcatch節へのコピーのどちらも、最適化されるかもしれないし、されないかもしれない。これは、一時オブジェクトでも、名前付きオブジェクトでも同様である。[5] 例:
#include <iostream>
struct C {
C() {}
C(const C&) { std::cout << "Hello World!\n"; }
};
void f() {
C c;
throw c; // 名前付きオブジェクト c を例外オブジェクトにコピー。
} // このコピーが省略されるかどうかは不確かである。
int main() {
try {
f();
}
catch(C c) { // 例外オブジェクトを例外宣言内の一時領域にコピー。
} // このコピーも省略されるかどうかは不確かである。
}
言語標準に準拠したコンパイラは、上記のコードから"Hello World!"と二度出力するプログラムを生成しなければならなかった。C++11では、名前付きオブジェクトの例外オブジェクトへのコピーと、例外ハンドラで宣言されたオブジェクトへのコピーを省略することを本質的に許した[5]ことで、その問題は対処された。
GCCは-fno-elide-constructors
オプションを提供して、コピーの省略を無効化できるようにしている。このオプションは戻り値最適化の効果を発見(あるいは見逃し!)するのに有用である。平時にこの重要な最適化を無効化することは推奨しない。
脚注
- ^ ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ ツァ12.8 Copying class objects [class.copy] para. 15
- ^ Sutter, Herb (2001). More Exceptional C++. Addison-Wesley
- ^ ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ ツァ15.1 Throwing an exception [except.throw] para. 5
- ^ ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ ツァ15.3 Handling an exception [except.handle] para. 17
- ^ a b “C++ Standard Core Language Defect Reports”. WG21. 2009年3月27日閲覧。