При каких обстоятельствах деструкторы C++ не собираются называться?

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

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

Есть ли какие-либо другие обстоятельства, где их не назовут?

43
задан WilliamKF 5 July 2010 в 12:39
поделиться

7 ответов

Есть ли другие обстоятельства, при которых они [деструкторы] не будут вызываться?

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

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

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

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

2
ответ дан 26 November 2019 в 22:58
поделиться

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

3
ответ дан 26 November 2019 в 22:58
поделиться

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

2
ответ дан 26 November 2019 в 22:58
поделиться

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

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

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

3
ответ дан 26 November 2019 в 22:58
поделиться

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

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

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

1
ответ дан 26 November 2019 в 22:58
поделиться

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

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

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

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

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

7
ответ дан 26 November 2019 в 22:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: