我刚开始使用c ++ boost库。我在许多地方读过,当使用scoped_ptr时,即使遇到异常,对象也总是被销毁。
我试过以下代码。
#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类的析构函数答案 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!!