例外処理 : MFC 3.0 での変更点
更新 : 2007 年 11 月
この情報は上級者が対象です。
MFC 3.0 以降では、C++ 例外処理機構を使うように例外処理マクロが変更されています。ここでは、この変更の影響を受ける既存コードの動作について説明します。
ここでは、次のトピックについて説明します。
例外の型と CATCH マクロ
例外の再スロー
例外の型と CATCH マクロ
MFC 2.5 以前では、CATCH マクロは、実行時の型情報に基づき、例外の型を判定していました。つまり、例外の型をキャッチ側で判定していました。C++ 例外処理機構では、必ずスロー側で例外の型を判定します。つまり、スローされる例外オブジェクトの型によって判定します。したがって、スローされたオブジェクトへのポインタの型とスローされたオブジェクト自体の型が異なる場合は、MFC の新旧バージョン間の互換性が失われます。
次に、MFC 2.5 と 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
MFC 3.0 では、例外宣言に一致する最初の catch ブロックに必ず制御が渡されます。
THROW( (CException*) new CCustomException() );
このスロー式の結果は、CCustomException として生成されていても、CException* としてスローされます。MFC 2.5 以前の CATCH マクロでは、CObject::IsKindOf を使って実行時に型をテストします。
e->IsKindOf(RUNTIME_CLASS(CException));
この式は True になるので、最初の catch ブロックが例外をキャッチします。MFC 3.0 では、C++ 例外を使って多くの例外処理マクロを実装しているので、2 番目の catch ブロックが CException と一致します。
このようなコードは一般的ではありません。通常、このようなコードを使うのは、例外オブジェクトを別の関数に渡し、その関数で汎用 CException* を受け取り、スローの前処理を行ってから、例外をスローする場合です。
この問題を回避するには、throw 式を関数から呼び出し側のコードに移し、例外生成時にコンパイラが認識できる実際の型の例外をスローします。
例外の再スロー
catch ブロックでは、キャッチした例外ポインタをそのままスローできません。
たとえば、次のコードは、以前のバージョンでは有効でしたが、MFC 3.0 では予期しない結果を引き起こします。
TRY
{
// Do something to throw an exception.
AfxThrowUserException();
}
CATCH( CException, e )
{
THROW( e ); // Wrong. Use THROW_LAST() instead
}
END_CATCH
}
THROW マクロを catch ブロック内で実行すると、ポインタ e が削除されます。この結果、外部の catch ブロックは無効なポインタを受け取ります。e を再スローするには、THROW_LAST を使います。
詳細については、「例外処理 : 例外のキャッチと削除」を参照してください。