受其他异常影响的异常的生命周期

Is the lifetime of an exception affected by other exceptions?

本文关键字:异常 生命 周期 影响 其他      更新时间: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
  }
  try
  {
    ReportError();
  }
  catch( ... )
  {
  }
}
void ReportError()
{
  throw SomeOtherError();
}

原始异常的"最后一个处理程序"(即main中的一个)在第二个异常被抛出时没有退出,所以两个异常都是活动的吗?一旦我们离开第二个异常的处理程序,原始异常是否仍然可用?

c++ 11 (N3242):

15.1p4:异常对象的内存以未指定的方式分配,除非在3.7.4.1中指出。如果一个处理程序通过重新抛出退出,将控制传递给同一异常的另一个处理程序。一个例外对象的最后剩余活动处理程序以任何其他方式退出后,将销毁该异常而不是重新抛出,或者引用异常对象的类型std::exception_ptr(18.8.5)的最后一个对象销毁,以较晚者为准。

(std::exception_ptr是c++ 11的特性,并没有在您的示例代码中使用)

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

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

15.1p8:没有操作数的throw-expression会重新抛出当前处理的异常(15.3)。

或者等价地,我认为,throw;总是指当前正在执行的最内层catch块捕获的异常。只是我没有像标准中定义的那样仔细地定义'最内部'和'执行'。

是的,一次可以分配多个异常对象,并且要求c++确保它们存在足够长的时间,以便在尝试重新抛出时做"正确的事情"。

不确定它有多标准,但如果我在HandleException的末尾添加throw;并用g++编译,结果程序告诉我:

root@xxxx [~/code]# ./a.out
terminate called after throwing an instance of 'SomeSpecificError'
  what():  17SomeSpecificError
Aborted

注意异常类型。这是MightThrow抛出的异常,而不是ReportError抛出的异常。

VS2010报告一个SomeSpecificError

一次只有一个"活动异常"。当您在异常处理程序中throw另一个异常时,实际上您正在更改正在堆栈中传播的异常的类型。

(顺便说一句,这一切都是必要的吗?你真的觉得这段代码容易读吗?) (更新)

关于标准参考…ISO/IEC 14882:2003,第15.3节[除。句柄],第8段为:

异常在进入处理程序时被认为已处理。(注意:堆栈将在那时展开。)

另一种说法是,一旦进入catch块,原始异常就不再活动。

同样,一旦进入catch块,uncaught_exception()函数将返回false。第15.5.3节[除非。未捕获)写道:

功能

bool uncaught_exception() throw()

在完成要抛出的对象的计算后返回true,直到完成在匹配处理程序中初始化异常声明(18.6.4)。这包括堆栈展开。如果异常被重新抛出(15.1), uncaught_exception()从重新抛出点返回true直到重新抛出的异常再次被捕获。

(更新2)

同样相关的是第15.3节第4段:

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

因此,一旦通过裸throw;以外的任何方式退出处理程序,原始异常就会被销毁。因此,如果您throw其他异常,则退出处理程序并销毁原始异常。