Share via


例外処理 : MFC 3.0 での変更点

この情報は上級者が対象です。

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 を使います。

詳細についてを参照してくださいの例外:キャッチし、例外を削除する

参照

概念

例外処理 (MFC)