[英]RAII and Stack unwinding
根据C ++ 03标准§15.3/ 9:
如果在程序中没有找到匹配的处理程序,则调用函数terminate(); 实现此定义(15.5.1)是在此对terminate()的调用之前是否取消堆栈的堆栈。
§15.5.1/ 1:
在以下情况下,必须放弃异常处理,以减少不太细微的错误处理技术:...当异常处理机制找不到引发异常的处理程序时(15.3)...
§15.5.1/ 2:
在这种情况下
void Terminate();
被称为(18.6.3)。 在没有找到匹配处理程序的情况下,实现是由实现定义的,在调用terminate()之前是否取消堆栈的堆栈。 在所有其他情况下,不得在调用terminate()之前解开堆栈。 根据确定展开过程最终会导致调用终止()的实现,不允许实现过早完成堆栈展开。
没错,从throw some_exception
到catch(some_exception)
发生了“堆栈展开”。 如果您的例外从未引起注意,我们将不知道会发生什么。
那是个大问题吗? 正如您所展示的,您只需要在某处添加catch(...)
即可捕获所有可能的异常,问题就消除了。
该标准定义了三种结束C ++程序执行的方式:
main
返回。 具有自动存储功能(本地功能)的对象已被破坏。 具有静态存储(全局,类静态,函数静态)的对象将被销毁。 std::exit
从<cstdlib>
std::exit
。 具有自动存储功能的对象不会被破坏。 具有静态存储的对象将被销毁。 <cstdlib>
std::abort
。 具有自动和静态存储的对象不会被破坏。 从<exception>
std::terminate
也与此有关。 可以使用std::set_terminate
替换terminate
行为,但是terminate
必须始终通过调用abort
或某些类似的实现特定的替代方法来“终止程序的执行”。 默认值为{ std::abort(); }
{ std::abort(); }
。
每当引发异常并且C ++无法合理地进行堆栈展开时,C ++就会调用std::terminate
。 例如,来自析构函数的异常(通过堆栈展开调用)或来自静态存储对象构造函数或析构函数的异常。 在这些情况下,将不执行(更多)堆栈展开操作。
当找不到匹配的catch
处理程序时,C ++也将调用std::terminate
。 在这种情况下,C ++可以选择在调用terminate
之前释放到main
。 因此,使用不同的编译器,您的示例可能会得到不同的结果。
因此,如果正确使用RAII,则“防泄漏”程序的其余步骤为:
std::abort
。 std::exit
或避免所有具有静态存储持续时间的对象。 catch (...)
处理程序放入main
,并确保在其中或之后没有任何分配或异常发生。 std::terminate
的其他编程错误。
throw()
规范一样,这意味着即使没有要调用的析构函数,也不能将异常“粘贴”给它们。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.