27

次の C++0x 標準では、ムーブ コンストラクター内またはムーブ コンストラクター中に例外がスローされるとどうなりますか?

元のオブジェクトは残りますか? または、元のオブジェクトと移動先オブジェクトの両方が未定義の状態ですか? 言語によって提供される保証は何ですか?

4

3 に答える 3

11

標準化委員会は当初、移動コンストラクターが例外をスローすることを許可しないようにしようとしたと思いますが、(少なくとも今日の時点で) それを強制しようとすると落とし穴が多すぎることがわかりました。

提案 N3050、「ムーブ コンストラクターのスローを許可する (Rev 1)」は、標準草案に組み込まれています。基本的に、この提案は移動コンストラクターがスローする機能を追加しますが、強力な例外安全性の保証が必要な特定の操作に「スロー」移動を使用できないようにします (非スロー移動がそうでない場合、ライブラリはオブジェクトのコピーにフォールバックします)。利用できません)。

ムーブ コンストラクターを非スロー ( noexcept) としてマークし、例外がスローされると、std::terminate() が呼び出されます。

N3050 が対処することを意図した問題について説明している David Abrahams によるブログ記事も読む価値があるかもしれません。

于 2011-01-19T06:44:14.280 に答える
3

移動元のタイプによって異なります。もちろん、move ctor から明示的に例外をスローすることもできますが、move ctor からサブオブジェクトの copy ctor を暗黙的に呼び出すこともできます。そのコピー ctor は、メモリの割り当てなど、スローされる可能性のある何かを実行する可能性があります。そのため、ソース オブジェクトの場合、元の値が残っている場合も残っていない場合もあるが、破壊可能な状態にあることが最低限保証されます。

移動先のオブジェクトについては、現在の C++ の ctor からスローするのと同じです。構築されたベースとメンバーを破棄し、ctor の関数 try ハンドラーがあればそれを実行し、例外を伝播します。詳細は N3225 §15.2p2 にあります。

特に、コンテナーでは、アロケーターの型にスローする移動 ctor がないことが必要であることに注意してください。

このようなアロケータのムーブ構築は、例外によって終了しません。[N3225 §23.2p8]

これにより、コンテナーはアロケーターを移動し、それらのアロケーターを使用して、アイテムの移動またはコピー時に例外が発生した場合にアイテムをクリーンアップできます。

于 2011-01-19T06:12:47.840 に答える
2

あなたの質問は、例外保証に関する質問になります。3 種類の例外保証 (関数に適用されます) があります。

  • 例外の保証はまったくありません(実際にはタイプではありません...しかし、問題に関心がなければ発生する可能性があります)
  • 基本的な例外の保証: 技術的には正しいが、機能的には正しくない (つまり、リソースはリークされず、プログラムは突然停止せずに終了しますが、支払いがキャッシュインされてもコマンドが登録されないなど、望ましくない副作用が生じる可能性があります)
  • 強力な例外保証: オール オア ナッシング (トランザクションのような)。つまり、すべてが正しく行われるか、前の状態にロールバックされます。
  • スロー例外なしの保証: これは決してスローしないので、心配はいりません。

関数を作成するときは、通常、独自の保証を持つ既存の関数を選択します。例外保証を増やすことは困難です。つまり、通常、使用される最も弱い保証によって制限されます。

あなたの質問に書いてあるように、例外がスローされた場合、元のオブジェクトをそのままにしておくには、少なくとも強力な例外保証が必要です。

では、 move-construction 中に例外がスローされた場合はどうなるでしょうか? それは、サブオブジェクトによって示される保証と、呼び出しを組み合わせた方法に依存します...

  1. コンストラクターから例外がスローされた場合、オブジェクトは構築されず、構築されたすべてのサブオブジェクトが逆の順序で破棄されます。このルールはムーブ コンストラクターにも適用されます。
  2. コンストラクターを try catch で "ラップ" し、移動されたオブジェクトを何らかの方法で復元しない限り、オブジェクトはリソースを失います。とにかく、それらはまだ破壊可能な状態にある必要があることに注意してください。したがって、技術的にはプログラムは正しいでしょう。

例外の保証に関しては、デフォルトで、すべてのサブオブジェクトのコンストラクターが少なくともBasic Exception Guaranteeを満たしている場合、move コンストラクターも特別な注意を払わなくても満たすことを意味します。

ただし、すべてのサブオブジェクトのコンストラクターがStrong Exception Guaranteeを満たしている場合でも、独自のムーブ コンストラクターがそれを満たすことに成功する可能性は低いです。これは、トランザクションの連鎖がトランザクションを生成しないのと同じ問題です。

サブオブジェクトのコンストラクターの 1 つだけがスローされる可能性があり、それがStrong Exception Guaranteeを満たす場合、最初にスローするオブジェクトを初期化すると、ムーブ コンストラクターはそれ自体を自然に満たします。

これが役に立てば幸いです...例外は飼いならす野獣です:)

于 2011-01-19T08:25:39.987 に答える