次の方法で共有


例外処理 : 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 を使います。

詳細については、「例外処理 : 例外のキャッチと削除」を参照してください。

参照

概念

例外処理 (MFC)