例外処理 : MFC 3.0 での変更点
これは高度なトピックです。
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 式を移動し、例外が生成されたときにコンパイラに認識されている実際の型の例外をスローします。
例外の再スロー
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
が削除されるため、外部のキャッチ サイトは無効なポインターを受け取ります。 e
を再スローするには、THROW_LAST を使用します。
詳細については、「例外処理: 例外のキャッチと削除」を参照してください。