使用scoped_ptr在异常情况下不调用析构函数

时间:2012-10-14 23:17:44

标签: c++ exception boost destructor scoped-ptr

我刚开始使用c ++ boost库。我在许多地方读过,当使用scoped_ptr时,即使遇到异常,对象也总是被销毁。

  

They behave much like built-in C++ pointers except that they automatically delete the object pointed to at the appropriate time. Smart pointers are particularly useful in the face of exceptions as they ensure proper destruction of dynamically allocated objects.

我试过以下代码。

#include<boost/scoped_ptr.hpp>

class B
{
  public:
    B(){ std::cout<< "B constructor call\n"; }
    ~B(){ std::cout<<"B destructor call\n"; }
};

class A
{
  public:
  boost::scoped_ptr<B> b;
  A():b(new B())  
  {
    throw 1;
  }
};

int main()
{
    A a; return 0;
}

output:
B constructor call
terminate called after throwing an instance of 'int'
Aborted (core dumped)

没有调用B的析构函数。但我使用scoped_ptr所以它应该调用B的析构函数或者我错误地解释了scoped_ptr的使用。

但如果用try catch环绕它,那么就会调用B的析构函数。

try{
  A a;
} catch( ... ) {
}

在这种情况下,A的析构函数将被调用为所有本地分配的对象,如果try块中的异常从堆栈中删除并且我的指针包含在内部并且scoped_ptr的对象因此当范围对象的析构函数破坏时最终指针。 所以scoped_ptr是有用的,因为我们不必显式删除分配的内存或我错误地解释了scoped_ptr的描述。

如果使用scoped_ptr

发生异常,如何调用B类的析构函数

2 个答案:

答案 0 :(得分:15)

没有匹配的异常处理程序,因此直接调用std::terminate,在这种情况下不会展开堆栈。将try / catch放在main中捕获int并且您将看到您的析构函数调用,即使该处理程序重新抛出。

C ++11§15.1/ 2:

  

当抛出异常时,控制权被转移到具有匹配类型的最近的处理程序; “nearest”表示最近由控制线程输入{{1>}关键字后面的复合语句 ctor-initializer 的处理程序退出。

和§15.3/ 9:

  

如果找不到匹配的处理程序,则调用函数try;在对std::terminate()的调用是否为实现定义之前,堆栈是否已展开。

<子> Online demo

答案 1 :(得分:0)

C ++在展开堆栈时销毁局部变量(从函数返回,使用return关键字或异常),因此它应该会看到一个破坏你的scoped_ptr。但在您的特殊情况下,main中发生异常,因此在C ++解除堆栈之前将调用terminate并终止您的程序。

void test() {throw 1;}
void main() {
    string sMain;
    test();
}

在上面的示例中,sMain不会被销毁,因为异常导致调用terminate

sMain constructed
exception occurred: main has no where to go, and it has no handler to handle
    the exception, so it will call `terminate`, but wait we are still at `main`
    so we have no stack unwinding here and sMain will never destroyed!!