В чем разница между функциями в .dtors
и функции, вызываемые с помощью atexit()
?
Как я понимаю, функции помечены ((destructor))
атрибут находится в .dtors
сегмент, и называется после выхода. Аналогично, функции добавлены с использованием atexit(fctName)
помещаются в массив и также вызывается после нормального завершения выполнения.
Так почему же C ++ предоставляет здесь два разных механизма? Есть ли отдельные вещи, которые можно сделать только с одним? Могу ли я только добавить функцию динамически, используя atexit()
?
Также которые называются во-первых, функции в .dtors
или функции, добавленные с помощью atexit()
?
От man-страницы linux atexit () вызывается при нормальном завершении процесса, либо через exit (3), либо через return из main () программы.
Что касается .ctors / .dtors, они вызываются, когда разделяемая библиотека, в которой они определены, загружается / выгружается.
Порядок, в котором они будут происходить, совершенно очевиден.
C ++ не имеет .dtors
, Некоторые реализации могут. Это разумный механизм для отслеживания деструкторов глобальных объектов. Насколько я понимаю, это список времени компиляции.
atexit
хотя обработчики добавляются во время выполнения. Это означает, что вы можете добавлять функции, только если и когда они становятся необходимыми во время выполнения.
Для последней части вашего вопроса (и более подробную информацию) см. Когда функция, зарегистрированная с помощью atexit (), называется
Одной из законных реализаций деструкторов статических объектов является регистрация
их с atexit
когда конструктор закончил. Стандарт
требует, чтобы порядок был таким же, как если бы использовалась эта реализация.
Основное отличие состоит в том, что деструкторы статических объектов являются
деструкторы: они будут вызваны автоматически, если объект
полностью построен, без необходимости с вашей стороны зарегистрироваться
их. И у них есть this
параметр для доступа к объекту.
РЕДАКТИРОВАТЬ:
Чтобы было совершенно ясно: дано
T obj; // where obj has static lifetime...
Компилятор сгенерирует функцию:
void __destructObj()
{
obj.~T();
}
и следующий код инициализации:
new (&obj) T;
std::atexit( __destructObj );
Это независимо от объема obj
; тот же основной код работает для
как локальная статика, так и объекты в области имен. (В случае
локальные объекты, компилятор также должен генерировать флаг и код
проверить его, чтобы указать, был ли объект уже инициализирован;
Также необходимо принять меры для обеспечения безопасности потока.)
На самом деле трудно понять, как компилятор мог бы сделать это иначе
(хотя он может генерировать встроенный код, чтобы сделать то, что std::atexit
делает),
учитывая требования к оформлению заказа.