При каких обстоятельствах деструкторы C ++ не будут вызываться? - PullRequest
42 голосов
/ 05 июля 2010

Я знаю, что мои деструкторы вызываются при обычном разматывании стека и когда генерируются исключения, но не при вызове exit ().

Есть ли другие случаи, когда мои деструкторы не будут вызываться?А как насчет сигналов, таких как SIGINT или SIGSEGV?Я предполагаю, что для SIGSEGV они не вызываются, но для SIGNINT они есть, как узнать, какие сигналы размотают стек?

Существуют ли другие обстоятельства, когда они не будут вызываться?

Ответы [ 8 ]

47 голосов
/ 05 июля 2010

Существуют ли другие обстоятельства, когда они [деструкторы] не будут вызваны?

  1. Прыжки в длину: они мешают процессу естественного разматывания стекаи часто приводят к неопределенному поведению в C ++.
  2. Преждевременные выходы (вы уже указали на это, хотя стоит отметить, что бросание при разматывании стека в результате выброса исключения приводит к неопределенному поведению, и именно поэтомумы никогда не должны выбрасывать из dtors)
  3. Бросок из конструктора не вызывает dtor для класса.Вот почему, если вы выделяете несколько блоков памяти, управляемых несколькими разными указателями (а не умными указателями) в ctor, вам нужно использовать блоки try на уровне функций или избегать использования списка инициализаторов и иметь блок try / catch в ctorbody (или, что еще лучше, просто используйте умный указатель, такой как scoped_ptr, так как любой член, успешно инициализированный до сих пор в списке инициализаторов, будет уничтожен, даже если класс dtor не будет вызываться).
  4. Как было указано, не удалосьсделать виртуальный dtor, когда класс удаляется через базовый указатель, может не удастся вызвать dtors подкласса (неопределенное поведение).
  5. Не удалось вызвать соответствующий оператор delete / delete [] для оператора new / new [] call(неопределенное поведение - может не вызвать dtor).
  6. Не удается вручную вызвать dtor при использовании размещения new с пользовательским распределителем памяти в разделе освобождения памяти.
  7. Использование функций, таких как memcpy, которая копирует толькоодин блок памяти в другой без вызова копий ctors.Функции mem * смертельно опасны в C ++, так как они обрабатывают личные данные класса, перезаписывают vtables и т. д. Результатом обычно является неопределенное поведение.
  8. Использование некоторых интеллектуальных указателей (auto_ptr) для неполного типа,смотри это обсуждение
7 голосов
/ 05 июля 2010

Стандарт C ++ ничего не говорит о том, как должны обрабатываться конкретные сигналы - многие реализации могут не поддерживать SIGINT и т. Д. Деструкторы не будут вызываться, если вызываются exit() или abort() или terminate().

Редактировать: Я только что провел быстрый поиск по стандарту C ++ и не могу найти ничего, что указывало бы, как сигналы взаимодействуют с временами жизни объектов - возможно, кто-то с лучшими стандартами, чемя мог что-то найти?

Дальнейшее редактирование: Отвечая на другой вопрос, я нашел это в Стандарте:

При выходе из области действия (хотя и выполнено), деструкторы (12.4)Вызываются для всех построенных объектов с автоматической продолжительностью хранения (3.7.2) (именованные объекты или временные объекты), которые объявлены в этой области, в обратном порядке их объявления.

Таким образом, кажется, что деструкторы должны вызываться при получении сигнала.

3 голосов
/ 05 июля 2010

Другой случай, когда они не будут вызваны, это если вы используете полиморфизм и не сделали свои базовые деструкторы виртуальными.

3 голосов
/ 05 июля 2010

Сигнал сам по себе не повлияет на выполнение текущего потока и, следовательно, на вызов деструкторов, потому что это другой контекст выполнения со своим собственным стеком, где вашобъекты не существуют.Это как прерывание: оно обрабатывается где-то за пределами контекста выполнения, и, если оно обрабатывается, элемент управления возвращается в вашу программу.

То же, что и в многопоточности, C ++ язык не делаетзнать понятие сигналов.Эти два полностью ортогональны друг другу и определены двумя не связанными стандартами.Как они взаимодействуют, зависит от реализации, если это не нарушает ни один из стандартов.

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

2 голосов
/ 25 января 2014

Здесь много ответов, но все еще не полностью!

Я обнаружил еще один случай, когда деструкторы не выполнялись. Это происходит всегда, когда исключение перехватывается через границы библиотеки.

Подробнее здесь:

Деструкторы не выполняются (без разматывания стека) при возникновении исключения

2 голосов
/ 05 июля 2010

Если функция или метод имеет спецификацию throws и генерирует что-то, НЕ включенное в спецификацию, поведение по умолчанию - немедленный выход. Стек не разматывается и деструкторы не вызываются.

Сигналы POSIX являются конструкцией, специфичной для операционной системы, и не имеют представления о области действия объекта C ++. Как правило, вы ничего не можете сделать с сигналом, кроме, может быть, перехватить его, установить глобальную переменную флага, а затем обработать это позже в коде C ++ после выхода из обработчика сигнала.

Последние версии GCC позволяют генерировать исключение из обработчиков синхронных сигналов, что приводит к ожидаемому процессу раскручивания и уничтожения. Это очень зависит от операционной системы и компилятора, хотя

2 голосов
/ 05 июля 2010

abort завершает программу, не выполняя деструкторы для объектов автоматического или статического хранения, как говорит Стандарт Для других ситуаций вы должны прочитать конкретные документы реализации.

1 голос
/ 05 июля 2010

Существуют в основном две ситуации, когда деструкторы вызываются: разматывание стека в конце функции (или при исключениях), если кто-то (или счетчик ссылок) вызывает delete.

Одна особая ситуация заключается вбыть найденным в статических объектах - они уничтожаются в конце программы с помощью at_exit, но это все еще вторая ситуация.

От того, какой сигнал пропускает проходящий at_exit, может зависеть, kill -9 немедленно убьет процесс,другие сигналы сообщат ему о выходе, но как именно это зависит от обратного вызова сигнала.

...