在scoped_ptr发生异常的情况下未调用析构函数

destructor not called in case of exception with scoped_ptr

本文关键字:情况下 调用 析构函数 异常 scoped ptr      更新时间:2023-10-16

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

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

我尝试了以下代码。

#include<boost/scoped_ptr.hpp>
class B
{
public:
B(){ std::cout<< "B constructor calln"; }
~B(){ std::cout<<"B destructor calln"; }
};
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的析构函数的调用。但我使用了scope_ptr,所以它应该调用B的析构函数,或者我错误地解释了scope_ptr。

但如果a用try-catch包围它,那么B的析构函数就会被调用。

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

在这种情况下,A的析构函数将被调用,因为在try块中出现异常的情况下,所有本地分配的对象都将从堆栈中删除,并且我的指针被包裹在scoped_ptr的对象中,所以当scoped对象的析构符最终销毁指针时。scope_ptr之所以有用,是因为我们不必显式删除分配的内存,或者我错误地解释了scope_ptr的描述。

在使用scope_ptr 发生异常的情况下,如何调用类B的析构函数

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

C++11§15.1/2:

当抛出异常时,控制权将转移到具有匹配类型的最近处理程序;"最近的"是指控件线程最近为其输入try关键字后的复合语句ctor初始值设定项但尚未退出的处理程序。

和§15.3/9:

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

在线演示

C++在展开堆栈时销毁局部变量(从函数返回,使用return关键字或有异常),因此它应该看到一个销毁scoped_ptr的变量。但在您的特殊情况下,异常发生在main中,因此terminate将被调用并在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!!