受嵌套处理程序影响的异常的生命周期

Is the lifetime of an exception affected by nested handlers?

本文关键字:异常 周期 生命 影响 嵌套 处理 程序      更新时间:2023-10-16

考虑以下代码片段:

struct ExceptionBase : virtual std::exception{};
struct SomeSpecificError : virtual ExceptionBase{};
struct SomeOtherError : virtual ExceptionBase{};
void MightThrow();
void HandleException();
void ReportError();
int main()
{
  try
  {
    MightThrow();
  }
  catch( ... )
  {
    HandleException();
  }
}
void MightThrow()
{
  throw SomeSpecificError();
}
void HandleException()
{
  try
  {
    throw;
  }
  catch( ExceptionBase const & )
  {
    // common error processing
  }
  try
  {
    throw;
  }
  catch( SomeSpecificError const & )
  {
    // specific error processing
  }
  catch( SomeOtherError const & )
  {
    // other error processing
  }
  ReportError();
}
void ReportError()
{
}

标准第15.1.4节告诉我们:

所抛出异常的临时副本的内存为以未指定的方式分配,除非在3.7.3.1中指出。的只要有正在执行的处理程序,临时就会持续存在这个例外。特别地,如果处理程序通过执行扔;语句,该语句将该控件的控制传递给另一个处理程序异常,因此临时保留。最后一个处理程序以除throw以外的任何方式执行异常退出;的临时对象被销毁,并且实现可以释放临时对象的内存;任何这样的重新分配都是在一种未指明的方式。破坏立即发生在类的异常声明中声明的对象的销毁处理程序。

我将main中的处理程序视为"最后一个处理程序"是否正确?因此,在HandleException中允许任何数量的重新抛出和捕获,而不会导致当前异常对象的破坏?

我是否正确地将main中的处理程序视为"最后一个处理程序" ?

是的,你是。

因此在HandleException中允许任意数量的重新抛出和捕获而不会导致当前异常对象的破坏?

是的。最后未处理的异常对象将被编译器生成的代码销毁。没有内存泄漏。

HandleException()中重新投掷是不好的。而不是1. 将捕获写入请求特定处理的任何异常类型;2. 您可以使用dynamic_cast对异常处理进行分组。捕获基异常类型并尝试将其向下强制转换为其任何派生异常类。但是dynamic_cast不是一个好的练习。因此,最好使用第一种解决方案。

最好这样重写你的代码:

struct ExceptionBase : virtual std::exception{};
struct SomeSpecificError : virtual ExceptionBase{};
struct SomeOtherError : virtual ExceptionBase{};
void MightThrow();
void HandleExceptionBase();
int main()
{
  try
  {
    MightThrow();
  }
  catch (SomeOtherError &error) {
    // first common code
    HandleExceptionBase();
    // react on this exception correctly
    // specific code
  }
  catch (SomeSpecificError &error) {
    // first common code
    HandleExceptionBase();
    // react on this exception correctly
    // specific code
  }
  catch (ExceptionBase &error) {
    HandleExceptionBase();
    // finally catch anything derived from base class
    // react on this exception correctly
  }
  catch(...) {
    // react on any other exception except 3 listed above
  }
}
void MightThrow()
{
  throw SomeSpecificError();
}
void HandleExceptionBase() {
  // base exception handler
}

感谢到目前为止张贴的评论和回答。我还没有看到我想要的东西,所以我将从aschpler提供的答案中添加一些信息到我的后续问题中。

15.3p7:当catch子句. ...的形式参数(如果有的话)初始化完成时,处理程序被认为是活动的一个处理程序当catch子句退出或Std::unexpected()在抛出后退出。

15.3p8:最近激活的处理程序仍然处于活动状态的异常称为当前处理的异常。

我认为这里的标准语言非常清楚,main实际上是最后一个处理程序。因此,异常的生命周期不受嵌套处理程序的影响。