これは高度なトピックです。
MFC バージョン 3.0 以降では、C++ 例外を使用するように例外処理マクロが変更されました。 この記事では、これらの変更がマクロを使用する既存のコードの動作にどのように影響するかを説明します。
この記事では、次のトピックについて説明します。
例外の種類と CATCH マクロ
以前のバージョンの MFC では、 CATCH マクロは MFC ランタイム型情報を使用して例外の型を決定しました。例外の型は、キャッチ サイトで決定されます。 ただし、C++ 例外では、例外の型は常にスローサイトでスローされる例外オブジェクトの型によって決定されます。 これにより、スローされたオブジェクトへのポインターの型がスローされたオブジェクトの型と異なるまれなケースでは非互換性が発生します。
次の例は、MFC バージョン 3.0 と以前のバージョンのこの違いの結果を示しています。
TRY
{
THROW((CException*) new CCustomException());
}
CATCH(CCustomException, e)
{
TRACE("MFC 2.x will land here\n");
}
AND_CATCH(CException, e)
{
TRACE("MFC 3.0 will land here\n");
}
END_CATCH
このコードはバージョン 3.0 では動作が異なります。コントロールは常に、一致する例外宣言を使用して最初の catch
ブロックに渡されるためです。 throw 式の結果
THROW((CException*) new CCustomException());
は、CCustomException
として構築されていても、CException*
としてスローされます。 MFC バージョン 2.5 以前の CATCH マクロでは、 CObject::IsKindOf
を使用して実行時に型をテストします。 式が
e->IsKindOf(RUNTIME_CLASS(CException));
が true の場合、最初の catch ブロックは例外をキャッチします。 C++ 例外を使用して多くの例外処理マクロを実装するバージョン 3.0 では、2 番目の catch ブロックはスローされた CException
と一致します。
このようなコードは一般的ではありません。 これは通常、ジェネリック CException*
を受け取り、"プリスロー" 処理を実行し、最後に例外をスローする別の関数に例外オブジェクトが渡されるときに表示されます。
この問題を回避するには、関数から呼び出し元のコードに throw 式を移動し、例外が生成された時点でコンパイラに認識されている実際の型の例外をスローします。
Re-Throwing 例外
catch ブロックは、キャッチしたのと同じ例外ポインターをスローできません。
たとえば、このコードは以前のバージョンでは有効でしたが、バージョン 3.0 では予期しない結果になります。
TRY
{
// Do something to throw an exception.
AfxThrowUserException();
}
CATCH(CException, e)
{
THROW(e); // Wrong. Use THROW_LAST() instead
}
END_CATCH
}
catch ブロックで THROW を使用すると、ポインター e
が削除されるため、外側の catch サイトは無効なポインターを受け取ります。
THROW_LASTを使用して、e
を再スローします。
詳細については、「 例外: 例外のキャッチと削除」を参照してください。