【问题标题】:C++: If an exception is thrown, are objects that go out of scope destroyed?C++:如果抛出异常,超出范围的对象是否被销毁?
【发布时间】:2015-02-18 16:30:42
【问题描述】:

通常它会在作用域结束时被破坏。但如果抛出异常,我会看到问题发生。

【问题讨论】:

  • 看看编译器可以使用 /FAs 生成的程序集列表。您不能错过确保它们被销毁的异常过滤器。

标签: c++ exception visual-studio-2008 scope throw


【解决方案1】:

是的。

C++ 标准 n3337

15 异常处理

§ 15.2 构造函数和析构函数

1) 当控制从 throw 表达式传递到处理程序时,析构函数 为自 try 块以来构造的所有自动对象调用 已输入。自动对象以相反的顺序销毁 他们的建设完成。

2) 任何存储持续时间的对象,其初始化或 破坏被异常终止将有析构函数 对其完全构造的子对象执行所有(不包括 类联合类的变体成员),也就是说,对于子对象 主构造函数 (12.6.2) 已完成执行并且 析构函数尚未开始执行。同样,如果 对象的非委托构造函数已完成执行,并且 该对象的委派构造函数以异常退出, 对象的析构函数将被调用。如果对象被分配在一个 new-expression,匹配的释放函数(3.7.4.2、5.3.4、 12.5),如果有的话,被调用来释放对象占用的存储空间。

3) 自动对象调用析构函数的过程 在从 try 块到 throw 表达式的路径上构造的是 称为“堆栈展开”。如果在堆栈期间调用了析构函数 展开以异常退出,调用 std::terminate (15.5.1)。 [注意:所以析构函数通常应该捕获异常而不是让 它们从析构函数中传播出来。 ——尾注]

示例:

SomeClass c;              // declared before try{} so it is
                          // still valid in catch{} block
try {
    SomeClass t;
    throw;
} catch( ...) {
    // t destroyed
    // c valid
}

【讨论】:

  • 假设class A 有一个互斥体成员变量。线程 T1 进入A::doSomething(),它使用堆栈创建的锁定对象锁定互斥锁。锁定互斥锁后,将引发未捕获的异常。互斥体是否曾被解锁?
【解决方案2】:

是的,任何范围绑定的变量都将被销毁。

void work()
{
     Foo a;
     Foo* b = new Foo;
     // ... later

     // exception thrown

     delete b;
}

在此示例中,a 的析构函数将在堆栈展开时引发异常时调用,但b 指向的内存将被泄漏,因为它永远不会到达delete 调用。这是 RAII 如此有用的众多原因之一。

【讨论】:

    【解决方案3】:

    是的。当您离开一个范围(无论是正常还是通过异常)时,该范围的本地对象将被销毁。这是使 RAII/SBRM 发挥作用的基本事实。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-18
      • 2014-03-06
      • 1970-01-01
      • 2013-09-28
      • 2012-09-20
      相关资源
      最近更新 更多