деструктор не вызывается в случае исключения с scoped_ptr

Я только начал использовать библиотеки 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.

Но если окружить его попыткой catch, то вызывается деструктор B.

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

В этом случае деструктор A будет вызываться, так как все локально расположенные объекты в случае исключения в блоке try удаляются из стека, и у меня есть мой указатель, заключенный внутрь, и объект scoped_ptr, поэтому, когда деструктор объекта scoped уничтожает, что в конечном итоге указатель ,
Так что scoped_ptr полезен, потому что нам не нужно явно удалять выделенную память, или я неправильно интерпретировал описание scoped_ptr.

Как я могу вызвать деструктор класса B в случае исключения, используя scoped_ptr

6

Решение

Там нет соответствующего обработчика исключений, поэтому std::terminate вызывается напрямую, в этом случае стек не разматывается. Положить try/catch в main что ловит int и вы увидите ваш вызов деструктора, даже если этот обработчик сработает.

C ++ 11 §15.1 / 2:

Когда генерируется исключение, управление передается ближайшему обработчику с соответствующим типом; «Ближайший» означает обработчик, для которого компаунд-заявление или же т е р-инициализатор следуя try Ключевое слово было недавно введено потоком управления и еще не завершено.

и §15.3 / 9:

Если соответствующий обработчик не найден, функция std::terminate() называется; действительно ли стек разматывается перед этим вызовом std::terminate() определяется реализацией.

Онлайн демо

15

Другие решения

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!!
0

По вопросам рекламы [email protected]