Здравствуйте, Went, Вы писали:
W>Здравствуйте. Хочется странного.
| Есть функция — геттер синглтона |
| W>W>Singleton& get_singleton()
W>{
W> static Singleton s_singleton;
W> return s_singleton;
W>}
W>
|
| |
W>По первому запросу объект создается, при разрушении статики — удаляется. Все хорошо.
W>Но иногда возникает ситуация, при которой происходят попытки обратиться к этому синглтону уже в процессе разрушения статики, и, иногда, уже после того, как переменная s_singleton разрушена.
W>Что делать? Я готов даже создавать новый экземпляр на куче или возвращать nullptr (допустим, функция возвращает указатель), но как надёжно определить тот факт, что статическая переменная уже разрушена? Можно поставить какой-то guard, который будет при разрушении ставить какую-то статическую переменную в особое состояние, но где гарантия, что дебагер, разрушая эту переменную, не затрёт её каким-то 0xDEADBEEF?
Если наш синглтон thread_local, то все танцы, связанные с синхронизацией отпадают. Тогда, думаю, достаточно будет просто сделать чуть более хитрую обертку (можно шаблонную):
http://coliru.stacked-crooked.com/a/36fdd30ff945e647
#include <iostream>
template <typename T>
T* get_singleton();
template <typename T>
class SingletonGuard
{
private:
SingletonGuard() = default;
SingletonGuard(const SingletonGuard&) = delete;
~SingletonGuard() { m_self_ptr = nullptr; };
friend T* get_singleton<T>();
T m_data{};
static thread_local SingletonGuard m;
static thread_local SingletonGuard* m_self_ptr;
};
template <typename T>
thread_local SingletonGuard<T> SingletonGuard<T>::m;
template <typename T>
thread_local SingletonGuard<T>* SingletonGuard<T>::m_self_ptr = &m;
template <typename T>
T* get_singleton()
{
// Такая строгая проверка практически сводит к нулю вероятность использования "мертвого" указателя
// на тот случай, если статическая память затирается каким-то специальным значением после использования.
return SingletonGuard<T>::m_self_ptr == &SingletonGuard<T>::m ? &SingletonGuard<T>::m.m_data : nullptr;
// Хотя, стого говоря, чтение значения из m_self_ptr, после окончания времени его жизни - это UB.
}
int main()
{
std::cout << get_singleton<int>() << std::endl;
}