X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Fsingleton.h;h=d051b4c96040e005ae7082d1fe034b1ec12979e0;hp=b3e4dfd324ab06e4ae8a45fbd9bbe5e059605705;hb=cc6e7c08709c4e761e2fd9c2e322751015497003;hpb=d19063654aa5fc2fd4cf7c111aac00803cf7c845 diff --git a/src/common/singleton.h b/src/common/singleton.h index b3e4dfd3..d051b4c9 100644 --- a/src/common/singleton.h +++ b/src/common/singleton.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2018 by the Quassel Project * + * Copyright (C) 2005-2019 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -20,7 +20,53 @@ #pragma once -#include +#include + +// For Windows DLLs, we must not export the template function. +// For other systems, we must, otherwise the local static variables won't work across library boundaries... +#ifndef Q_OS_WIN +# include "common-export.h" +# define QUASSEL_SINGLETON_EXPORT COMMON_EXPORT +#else +# define QUASSEL_SINGLETON_EXPORT +#endif + +namespace detail { + +// This needs to be a free function instead of a member function of Singleton, because +// - MSVC can't deal with static attributes in an exported template class +// - Clang produces weird and unreliable results for local static variables in static member functions +// +// We need to export the function on anything not using Windows DLLs, otherwise local static members don't +// work across library boundaries. +template +QUASSEL_SINGLETON_EXPORT T* getOrSetInstance(T* instance = nullptr, bool destroyed = false) +{ + static T* _instance = instance; + static bool _destroyed = destroyed; + + if (destroyed) { + _destroyed = true; + return _instance = nullptr; + } + if (instance) { + if (_destroyed) { + std::cerr << "Trying to reinstantiate a destroyed singleton, this must not happen!\n"; + abort(); // This produces a backtrace, which is highly useful for finding the culprit + } + if (_instance != instance) { + std::cerr << "Trying to reinstantiate a singleton that is already instantiated, this must not happen!\n"; + abort(); + } + } + if (!_instance) { + std::cerr << "Trying to access a singleton that has not been instantiated yet!\n"; + abort(); + } + return _instance; +} + +} // detail /** * Mixin class for "pseudo" singletons. @@ -47,24 +93,16 @@ public: * * @param instance Pointer to the instance being created, i.e. the 'this' pointer of the parent class */ - Singleton(T *instance) + Singleton(T* instance) { - if (_destroyed) { - qFatal("Trying to reinstantiate a destroyed singleton, this must not happen!"); - abort(); // This produces a backtrace, which is highly useful for finding the culprit - } - if (_instance) { - qFatal("Trying to reinstantiate a singleton that is already instantiated, this must not happen!"); - abort(); - } - _instance = instance; + detail::getOrSetInstance(instance); } // Satisfy Rule of Five - Singleton(const Singleton &) = delete; - Singleton(Singleton &&) = delete; - Singleton &operator=(const Singleton &) = delete; - Singleton &operator=(Singleton &&) = delete; + Singleton(const Singleton&) = delete; + Singleton(Singleton&&) = delete; + Singleton& operator=(const Singleton&) = delete; + Singleton& operator=(Singleton&&) = delete; /** * Destructor. @@ -73,8 +111,7 @@ public: */ ~Singleton() { - _instance = nullptr; - _destroyed = true; + detail::getOrSetInstance(nullptr, true); } /** @@ -85,23 +122,8 @@ public: * * @returns A pointer to the instance */ - static T *instance() + static T* instance() { - if (_instance) { - return _instance; - } - qFatal("Trying to access a singleton that has not been instantiated yet"); - abort(); + return detail::getOrSetInstance(); } - -private: - static T *_instance; - static bool _destroyed; - }; - -template -T *Singleton::_instance{nullptr}; - -template -bool Singleton::_destroyed{false};