从析构函数中抛出异常的主要问题是,在析构函数被调用的时刻,另一个异常可能是“in flight”(std :: uncaught_exception()== true),因此在这种情况下不太明显.用新的例外覆盖旧的例外将是处理这种情况的可能办法之一.但是,在这种情况下,必须调用std :: terminate(或另一个std :: terminate_handler).
C 11通过std :: nested_exception类引入了嵌套异常功能.该特征可以用于解决上述问题.旧的(未捕获的)异常可以嵌套在新的异常中(反之亦然),然后可以抛出嵌套的异常.但是这个想法没有被使用.在C11和C14这种情况下,std :: terminate仍然被称为.
所以问题.是否考虑嵌套异常的想法?有什么问题吗? C 17中情况不会改变吗?
解决方法
当您的析构函数作为堆栈展开过程的一部分(当您的对象未作为堆栈展开的一部分创建)1执行时,您引用的问题发生,您的析构函数需要发出异常.
那么这是如何工作的?你有两个例外.异常X是导致堆栈展开的异常.异常Y是析构函数想要抛出的异常. nested_exception只能容纳其中之一.
所以也许你有异常Y包含一个nested_exception(或者也许只是一个exception_ptr).那么…你在处理这个网站时怎么处理?
如果你抓到Y,它恰好有一些嵌入X,你怎么得到它?记住:exception_ptr被删除;除了传递它,你唯一可以做的是推翻它.人们也应该这样做:
catch(Y &e) { if(e.has_nested()) { try { e.rethrow_nested(); } catch(X &e2) { } } }
我看不到很多人这样做.特别是因为X-es可能会有非常大的数量.
1:请不要使用std :: uncaught_exception()== true来检测这种情况.这是非常有缺陷的.