6

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

它们的行为很像内置的 C++ 指针,只是它们会在适当的时候自动删除指向的对象。智能指针在面对异常时特别有用,因为它们确保正确销毁动态分配的对象。

我尝试了以下代码。

#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 的使用。

但是如果 a 用 try catch 包围它,则调用 B 的析构函数。

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

在这种情况下, A 的析构函数将被调用,因为在 try 块中出现异常的情况下,所有本地分配的对象都从堆栈中删除,并且我将指针包裹在里面和 scoped_ptr 的对象,所以当作用域对象的析构函数最终销毁指针时. scoped_ptr 也很有用,因为我们不必显式删除分配的内存,否则我误解了 scoped_ptr 的描述。

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

4

2 回答 2

15

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

C++11 §15.1/2:

当抛出异常时,控制权被转移到最近的具有匹配类型的处理程序;“最近”是指关键字后面的复合语句ctor-initializertry最近由控制线程进入但尚未退出的处理程序。

和§15.3/9:

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

在线演示

于 2012-10-14T23:27:41.340 回答
0

C++ 在展开堆栈时销毁局部变量(从函数返回,使用return关键字或异常),所以它应该看到一个销毁你的scoped_ptr. 但是在您的特殊情况下,发生的异常mainterminate在 C++ 展开堆栈之前被调用并终止您的程序。

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!!
于 2012-10-14T23:58:40.637 回答