作为my previous question的后续行动:
如果我更改代码如下:
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
中的那个)在抛出第二个异常时没有退出,那么两个异常都是活动的吗?一旦我们离开第二个例外的处理程序,原始异常是否仍然可用?
答案 0 :(得分:2)
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 ++来确保它们足够长,以便在您尝试重新抛出时做“正确的事情”。
答案 1 :(得分:1)
不确定它是多么标准,但是如果我在throw;
结尾之前添加HandleException
并使用g ++编译,则生成的程序会告诉我:
root@xxxx [~/code]# ./a.out
terminate called after throwing an instance of 'SomeSpecificError'
what(): 17SomeSpecificError
Aborted
注意异常类型。这是MightThrow
中引发的异常,而不是来自ReportError
的异常。
VS2010也会报告SomeSpecificError
。
答案 2 :(得分:0)
一次只有一个“活动例外”。当您在异常处理程序中throw
另一个异常时,实际上您正在更改正在向上传播的异常的类型。
(顺便说一下,这一切都是必要的吗?你真的觉得这段代码很容易阅读吗?)
[更新]
至于标准参考文件...... ISO / IEC 14882:2003,第15.3节[除了手柄],第8段内写着:
在进入处理程序时会考虑处理异常。 [注意: 堆栈将在那时解开。 ]
另一种说法是,只要您输入catch
块,原始异常就不再有效。
此外,只要输入uncaught_exception()
块,false
功能就会返回catch
。第15.5.3节[except.uncaught]读取:
功能
bool uncaught_exception() throw()
在完成对要抛出的对象的评估之后返回true,直到完成 在匹配处理程序中初始化异常声明 (18.6.4)。这包括堆栈展开。如果重新抛出异常 (15.1),uncaught_exception()从rethrow返回true 直到再次捕获重新抛出的异常。
[更新2]
同样相关的是第15.3节第4段:
抛出异常的临时副本的内存是 除非在3.7.3.1中指出,否则以未指明的方式分配。该 只要有正在执行的处理程序,临时就会持久存在 那个例外。特别是,如果处理程序通过执行a退出
throw;
语句,将控制权传递给另一个处理程序 例外,所以临时遗体。当最后一个处理程序正在 通过throw;
之外的任何方式执行异常退出 临时对象被销毁,实现可能会解除分配 临时对象的内存;任何这样的解除分配都是在 一种未说明的方式。破坏后立即发生破坏 破坏在异常声明中声明的对象 处理程序。
因此,只要处理程序通过除throw;
之外的任何其他方式退出,原始异常就会被销毁。因此,如果您throw
有其他异常,则退出处理程序并销毁原始异常。