异常:版本 3.0 中异常宏的更改

这是一个高级主题。

在 MFC 版本 3.0 及更高版本中,异常处理宏已更改为使用C++异常。 本文介绍了这些更改如何影响使用宏的现有代码的行为。

本文涵盖以下主题:

异常类型和 CATCH 宏

在早期版本的 MFC 中, CATCH 宏使用 MFC 运行时类型信息来确定异常的类型;异常的类型在 catch 站点确定,换句话说。 但是,由于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((CException*) new CCustomException());

被引发为 a CException*,即使它构造为 a CCustomException。 MFC 版本 2.5 及更早版本中的 CATCH 宏用于 CObject::IsKindOf 在运行时测试类型。 因为表达式

e->IsKindOf(RUNTIME_CLASS(CException));

为 true,第一个 catch 块捕获异常。 在版本 3.0 中使用C++异常来实现许多异常处理宏,第二个 catch 块与引发 CException的宏匹配。

此类代码并不常见。 当异常对象传递给接受泛型 CException*、执行“预引发”处理并最终引发异常的另一个函数时,它通常会出现。

若要解决此问题,请将引发表达式从函数移动到调用代码,并在生成异常时引发编译器已知的实际类型的异常。

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

有关详细信息,请参阅 异常:捕获和删除异常

另请参阅

异常处理