直到我对RAII和堆栈解开的“相互缠绕”(因为没有更好的词)的概念是完全错误的(如果不是完全的话)。我的理解是,使用RAII,可以防止任何/所有资源泄漏-即使是可能由未处理的异常引起的泄漏。
然而,编写this test program并随后偶然发现this article/documentation,使我意识到堆栈展开只会导致启用RAII的资源释放在try块内为automatic而不是automatic在外部/其他作用域中发挥作用。
我对这个(新)理解是正确的吗?或者我还没有掌握更多的细微差别?有没有大师想加入进来?指向任何好的文章/分析/解释(堆栈展开)的指针将对…很有帮助/很受欢迎
发布于 2011-04-06 03:50:49
来自C++03标准,§15.3/9:
如果在程序中找不到匹配的处理程序,则调用函数terminate();在调用terminate()之前是否展开堆栈取决于实现定义(15.5.1)。
§15.5.1/1:
在以下情况下,必须放弃异常处理,以便使用不太细微的错误处理技术:...当异常处理机制找不到抛出异常(15.3)的处理程序时...
§15.5.1/2:
在这种情况下,调用
();(18.6.3)。在未找到匹配处理程序的情况下,在调用terminate()之前是否展开堆栈由实现定义。在所有其他情况下,在调用terminate()之前不应展开堆栈。基于展开过程最终将导致调用terminate()的确定,不允许实现过早地完成堆栈展开。
发布于 2011-04-06 04:08:37
您说得对,“堆栈展开”发生在从throw some_exception到catch(some_exception)的过程中。如果你的异常没有达到一个catch,我们就不知道会发生什么。
这是个大问题吗?正如您所展示的那样,您只需在某个位置添加一个catch(...)来捕获所有可能的异常,问题就会消失。
发布于 2011-04-07 00:34:55
该标准定义了三种结束C++程序执行的方法:
main返回。具有自动存储(函数本地)的对象已被销毁。具有静态存储(全局、类静态、函数静态)的对象将从<cstdlib>进行destroyed.std::exit。具有自动存储的对象不会被销毁。具有静态存储的对象将是来自<cstdlib>的destroyed.std::abort。具有自动和静态存储的对象不会销毁。同样相关的还有来自<exception>的std::terminate。可以使用std::set_terminate替换terminate的行为,但terminate必须始终通过调用abort或某种类似的特定于实现的替代方法来“终止程序的执行”。默认值仅为{ std::abort(); }。
无论何时抛出异常,C++都会调用std::terminate,而C++无法合理地进行堆栈展开。例如,来自由堆栈展开调用的析构函数的异常,或者来自静态存储对象构造函数或析构函数的异常。在这些情况下,不会进行(更多)堆栈展开。
当找不到匹配的catch处理程序时,C++还将调用std::terminate。在这种情况下,在调用terminate之前,C++可能会选择性地展开到main。因此,使用不同的编译器,您的示例可能会有不同的结果。
因此,如果您正确使用RAII,则要“防泄漏”您的程序的其余步骤如下:
std::exit或所有具有静态存储的对象避免main中的catch (...)处理程序,并确保在它期间或之后没有发生分配或异常。std::terminate的编程错误。析构函数(throw()规范,这意味着即使没有析构函数作为解构函数,也不能抛出异常
https://stackoverflow.com/questions/5557555
复制相似问题