首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RAII和堆栈展开

RAII和堆栈展开
EN

Stack Overflow用户
提问于 2011-04-06 03:42:16
回答 3查看 1.8K关注 0票数 0

直到我对RAII和堆栈解开的“相互缠绕”(因为没有更好的词)的概念是完全错误的(如果不是完全的话)。我的理解是,使用RAII,可以防止任何/所有资源泄漏-即使是可能由未处理的异常引起的泄漏。

然而,编写this test program并随后偶然发现this article/documentation,使我意识到堆栈展开只会导致启用RAII的资源释放在try块内为automatic而不是automatic在外部/其他作用域中发挥作用。

我对这个(新)理解是正确的吗?或者我还没有掌握更多的细微差别?有没有大师想加入进来?指向任何好的文章/分析/解释(堆栈展开)的指针将对…很有帮助/很受欢迎

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 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()的确定,不允许实现过早地完成堆栈展开。

票数 5
EN

Stack Overflow用户

发布于 2011-04-06 04:08:37

您说得对,“堆栈展开”发生在从throw some_exceptioncatch(some_exception)的过程中。如果你的异常没有达到一个catch,我们就不知道会发生什么。

这是个大问题吗?正如您所展示的那样,您只需在某个位置添加一个catch(...)来捕获所有可能的异常,问题就会消失。

票数 2
EN

Stack Overflow用户

发布于 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的编程错误。析构函数(
    • )(在某些实现中,使用C编译器编译的函数的行为就像它们具有C++的空throw()规范,这意味着即使没有析构函数作为解构函数,也不能抛出异常

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5557555

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档