atexit для одноэлементного уничтожения: случай сбоя

Из: https://sourcemaking.com/design_patterns/to_kill_a_singleton

Одно можно сказать наверняка: вы не можете использовать более одного разрушителя, если одноэлементные деструкторы зависят друг от друга. В качестве альтернативы можно вообще отказаться от разрушителей и вместо этого полагаться на стандартную функцию atexit(), как предложил мне Тим Пайерлс: срок службы и замены нет.

Проект стандарта обещает многое: функция atexit() from может использоваться для указания функции, которая будет вызываться при выходе. Если должен быть вызван atexit(), реализация не должна уничтожать объекты, инициализированные до вызова atexit(), до тех пор, пока не будет вызвана функция, указанная в вызове atexit().

Единственный способ, которым я вижу эту ошибку, - это если статически инициализированный объект, деструктор которого зависит от экземпляра Singleton, инициализируется после создания экземпляра Singleton, т. е. посредством какой-либо другой статической инициализации. Это говорит о том, что классы, имеющие статические экземпляры, должны избегать зависимости от синглетонов во время уничтожения. (Или, по крайней мере, должен быть способ для таких классов проверять существование синглтона во время уничтожения.)

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

Может кто-нибудь, пожалуйста, пролить свет на это.


person q126y    schedule 13.01.2016    source источник


Ответы (1)


Поскольку для очистки синглтонов вместо деструкторов используется atexit, порядок очистки объектов можно изменить. Например:

Singleton S;
Object O;
// later in code:
Call atexit() to register cleanup function for S

Обычно порядок уничтожения для этих объектов будет следующим: O, затем S, но с добавлением вызова atexit он меняется на противоположный, так что S очищается при вызове atexit, а затем уничтожается O. Если деструктор O каким-либо образом зависит от Singleton S, у вас будет неопределенное поведение во время работы этого деструктора.

Способ избежать этого — вызвать atexit для регистрации функции очистки Singleton перед созданием любых объектов, которые от нее зависят. Если O сам является статическим объектом, это может быть сложно и может потребовать создания класса, конструктор которого вызывает atexit, чтобы его можно было вставить между двумя статическими объектами.

Singleton S;
struct SAtExit {
     SAtExit() { atexit(...); }
} SCleanup;
Object O;
person 1201ProgramAlarm    schedule 13.01.2016