別のメソッドで戻り値の代わりに例外をスローするライブラリ プロジェクトの 1 つに取り組んでいたときに、好奇心から生じた一般的な質問をしていますが、その例外を戻り値に変換したいと考えています。複数の try catch ブロックを使用して解決しましたが、C++ で例外がスローされた後に再開する方法があることを知りたいだけです。
3 に答える
私はあなたが何を望んでいるのか完全にはわかりません。例外を戻りコードに変換しても、例外の後で再開されません。C++ 委員会は再開を検討しましたが、それが何を意味するのかは明確ではありませんでした。検討:
int
someFunction()
{
// ...
if ( someCondition ) {
throw SomeException();
}
assert( !someCondition );
// ...
}
C++ では、assert
がトリガーされることはありません (そして、と はアサートされた条件が後で有効であることを明確にするため、通常はそれを記述しません) if
。throw
例外を再開できる場合は、assert
would (または少なくとも might) がトリガーされます。コード検証の重要な手段を失うことになります。
また、他の言語でそれを使用したことがある人は、実際にはうまく機能しないと報告しており、再開を使用し始めたすべてのケースで、後で使用しないようにコードを変更する必要がありました。
いいえ。実際、コンパイラは、例外がスローされた後、到達不能なコードの命令を発行することさえできない場合があります。
throw std::invalid_argument;
int i = 5; // No instructions generated for this, as it is unreachable.
resume
安全に動作する命令を作成するには、 の直後でthrow
はなく、その前の の直前にジャンプif
して、条件を再テストする必要があります。
ここでの問題は、C++ の例外が考えられる方法によって、それらはステートメント自体であり、必ずしも即時の条件分岐ではないということです。(if
とthrow
は互いに独立して定義されます)
また、 と の間にthrow
(catch
外部でいくつかの関数呼び出しが含まれる場合があります)、「スタック アンローリング」という名前のものがあります。これは、すべてのローカルのすべてのデストラクタを実際に呼び出し、エスケープする必要があるブロックに残されます。" resume
" はこれらすべてのオブジェクトを再構築する必要がありますが、そのようなデストラクタのアクションはスロー命令自体に依存せず、「元に戻せない」可能性があるため、システム状態を一貫して復元することはほとんど不可能です。
可能なイディオムは
for(;;)
{
try
{
... everything may throw ...
break; //if you are here everything was successful, so stop looping and go on
}
catch(whatever_you_may)
{
try_to_repair;
if(impossible) throw;
}
}
実際には、成功するか、そうではないと判断するまでループします。
ただし、これが再構築 (または非破壊) ではなく、再実行であることに注意してください。