Время жизни объекта C ++ начинается только после успешного завершения его конструктора.
Поскольку исключение было выдано до завершения вызова конструктора, у вас нет завершенного объекта и, следовательно, нет деструктора.
Херб Саттер объясняет это прекрасно , чтобы процитировать его:
Q: Что означает создание исключения из конструктора?
A: Это означает, что строительство не удалось, объект никогда не существовал, его время жизни никогда не начиналось. Действительно, единственный способ сообщить о неудаче построения, то есть о невозможности правильно построить функционирующий объект данного типа, - это вызвать исключение. (Да, существует ныне устаревшее соглашение о программировании, которое гласило: «Если у вас возникли проблемы, просто установите флаг состояния на« плохой »и позвольте вызывающему проверить его с помощью функции IsOK ()». Я прокомментирую это сейчас .)
В биологическом отношении,
зачатие состоялось - конструктор начал - но, несмотря на все усилия, за ним последовал выкидыш - конструктор так и не дотянулся до срока (начала).
Кстати, , поэтому деструктор никогда не будет вызван, если конструктор не преуспел - нечего уничтожать. "It cannot die, for it never lived."
Обратите внимание, что это делает фразу "an object whose constructor threw an exception"
действительно оксюмороном. Такая вещь даже меньше, чем бывший объект ... она никогда не жила, никогда не была, никогда не дышала первой. Это не объект.
Мы можем обобщить модель конструктора C ++ следующим образом:
Или:
(a) Конструктор обычно возвращается, достигнув своего конца или оператора возврата, и объект существует.
Или:
(b) Конструктор завершается созданием исключения, и объект не только не существует, но и никогда не существовал как объект.
РЕДАКТИРОВАТЬ 1:
Но если исключение произойдет в main()
, т.е. после того, как объект MyClass
будет полностью создан, будет ли вызван деструктор MyClass
?
Да, будет!
Это цель использования scoped_ptr
. Как только исключение выдается в main
, разматывание стека приведет к освобождению всех локальных объектов, это означает, что myinst
(который находится в стеке) также будет освобожден, что в Ход вызовет деструктор MyClass
.
См. Ускоренная документация , если сомневаетесь:
Шаблон класса scoped_ptr
хранит указатель на динамически размещенный объект. (Динамически размещенные объекты выделяются с помощью нового выражения C ++.) Указанный объект гарантированно будет удален либо при уничтожении scoped_ptr
, либо с помощью явного reset
РЕДАКТИРОВАТЬ 2:
Почему ваша отредактированная программа вылетает?
Ваша программа показывает сбои, потому что, вы бросаете исключение, но никогда его не ловите. когда происходит такой сценарий, вызывается специальная функция с именем terminate()
, поведение по умолчанию для вызова abort()
. Это поведение, определяемое реализацией, независимо от того, является ли стек размотанным до вызова terminate()
в этом конкретном сценарии Ref 1 . Кажется, ваша реализация не так, и вы не должны полагаться на это поведение.
Вы можете изменить свою программу следующим образом, чтобы обработать исключение, и вы должны получить ожидаемое поведение:
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
void doSomething()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
throw 3;
}
int main()
{
try
{
doSomething();
}
catch(int &obj)
{
std::cout<<"Exception Handled";
}
}
Ref 1 C ++ 03 15.5.1 Функция terminate ()
В следующих ситуациях обработка исключений должна быть прекращена для менее тонких методов обработки ошибок:
....
- когда механизм обработки исключений не может найти обработчик для брошенного исключения (15.3),
....
В таких случаях
- void terminate ();
называется (18.6.3).В ситуации, когда соответствующий обработчик не найден, определяется реализацией, будет ли стек разматываться перед вызовом terminate()
.Во всех других ситуациях стек не должен быть размотан до вызова terminate()
.Реализация не может досрочно завершить разматывание стека на основании определения, что процесс разматывания в конечном итоге вызовет terminate()
.