От : https://sourcemaking.com/design_patterns/to_kill_a_singleton
Одно можно сказать наверняка: вы не можете использовать более одного разрушителя, если
Синглтонные деструкторы зависят друг от друга. Альтернативой является
полностью избегать эсминцев и вместо этого полагаться на проект стандарта
Функция atexit (), как предложил мне Тим Пайерлс: я утверждаю, что
atexit () — это хороший способ очистки синглетонов в C ++, когда вы действительно
хотите единичные экземпляры с продолжительностью жизни программы и без замены.Проект стандарта обещает многое: функция atexit () может быть
используется для указания функции, вызываемой при выходе. Если atexit () должен быть
вызывается, реализация не должна уничтожать инициализированные объекты
до вызова atexit () до тех пор, пока функция, указанная в
Вызов atexit () был вызван.Единственный способ увидеть этот сбой — статически инициализированный
инициализируется объект, деструктор которого зависит от экземпляра Singleton
после экземпляр Singleton создается, то есть, посредством некоторой другой статической инициализации. Это говорит о том, что классы, имеющие статические
экземпляры следует избегать зависимости от синглетонов при уничтожении. (Или же
по крайней мере, для таких классов должен быть способ проверить
Существование Синглтона при уничтожении.)
Я не мог понять последний абзац, то есть, в каком случае он потерпит неудачу и как.
Может кто-нибудь, пожалуйста, пролить свет на это.
Так как это использует atexit
вместо деструкторов для очистки Singletons, порядок очистки объекта может быть изменен. Например:
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;
Других решений пока нет …