8

何か問題が発生した場合のクリーンアップにRAIIを使用しているクラスがあります。これは、クラスに作業が完了したかどうかを示すフラグが含まれていることを意味します。コンストラクターが呼び出されたときにこのフラグが設定されていない場合、クラスはクリーンアップタスクを実行し、ログメッセージを生成します。今、私はこのクラスをもう一歩賢くしたいと思います。つまり、エラーが発生したのか、作業が中止されたのか(つまり、例外がスローされてデストラクタが呼び出されたのか)、または誰かがこのクラスを誤用して、決して実際に作業を終了しました。これは、例外がアクティブであるかどうかをデストラクタで確認する必要があることを意味します。見つかった場合は、ログメッセージを生成し、例外の内容を出力してから再スローする可能性があります。こんな感じだと思います。

Foo::~Foo () {
  try { /* do not know what to put here */ }
  catch( const std::exception & ex ) {
     // produce error in log
     throw;
  }
  catch( ... ) {
    // produce some other log message
    throw;
   }
}

tryただし、デストラクタが呼び出される前に例外がすでにアクティブであり、ブロックから発生していないため、これが機能するかどうかはわかりません。また、私はthrow;デストラクタの内部を使用しており、この時点で例外をスローすることは本当に悪い考えです。したがって、このケースがこのルール(私にはわかりません)の例外(しゃれは意図されていません)であることが標準で明確に保証されていない限り、私はそれを行いません。

それで、これはまったく可能ですか、それとも他の方法でこの状況に対処する必要がありますか?

4

3 に答える 3

12

std::uncaught_exception()例外がスローされたが、catchまだそれを処理していない場合は、true を返す whichを使用できます。デストラクタでこのチェックを使用して、何をすべきか、何をすべきでないかを決定できます。

良いプログラミング ガイドラインでは、デストラクタがさまざまな状況で大きく異なる動作をすることは、通常は良い考えではないことに注意してください。したがって、この関数を使用しますが、乱用しないでください。一般的な使用法は、キャッチされていないアクティブな例外がない場合にのみスローするデストラクタを使用することです (この関数は false を返します)。しかし、そのような動作は一般的に良い設計ではありません。例外が必要なほど状態が悪い場合は、おそらく無視すべきではありません。とにかく、デストラクタは例外をスローすべきではありません。

例:

Foo::~Foo()
{
    if (std::uncaught_exception()) 
    {
        std::cerr << "Warning: Can't cleanup properly" << std::endl;
        return;
    }
    else
    {
        // ...
    }
}
于 2011-04-01T10:01:49.003 に答える
2

安全な方法で行うことはできません。

できることは、デストラクタでパラメータを確認することです。これにより、処理が完了したかどうかがわかります。

ところで、実際にエラーを処理できる catch ブロックにエラーを記録しないのはなぜですか? そこで、処理がエラーで終了したことがわかるはずです。

于 2011-04-01T09:48:20.117 に答える
1

私のこの質問と回答を見てください。

throw基本的に、最初のtryブロックでsimpleを使用して、現在アクティブな例外を再スローできます。ただし、これは、現在処理されている例外があることを確実に知っている場合、つまり、catchブロック内からデストラクタが呼び出された場合にのみ安全です。それ以外の場合は、throwを呼び出しstd::terminate()ます。

Foo::~Foo () {
  try {  throw; } // only if you *know* that an exception is active - bad thing for a generic destructor
  catch( const std::exception & ex ) {
     // produce error in log

  }
  catch( ... ) {
    // produce some other log message

   }
}

ただし、デストラクタ内から例外をスローすることは嫌われているので、後で例外を再スローすることはしません。結局のところ、すべてが私には良い考えのようには見えません。

例外処理パターンは問題ありませんが、無関係のデストラクタでは実行しません。繰り返しますが、参照されている質問を参照してください。

于 2011-04-01T09:37:22.580 に答える