1 /***************************************************************************
2 * Copyright (C) 2005-2018 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
25 // For Windows DLLs, we must not export the template function.
26 // For other systems, we must, otherwise the local static variables won't work across library boundaries...
28 # include "common-export.h"
29 # define QUASSEL_SINGLETON_EXPORT COMMON_EXPORT
31 # define QUASSEL_SINGLETON_EXPORT
36 // This needs to be a free function instead of a member function of Singleton, because
37 // - MSVC can't deal with static attributes in an exported template class
38 // - Clang produces weird and unreliable results for local static variables in static member functions
40 // We need to export the function on anything not using Windows DLLs, otherwise local static members don't
41 // work across library boundaries.
43 QUASSEL_SINGLETON_EXPORT T* getOrSetInstance(T* instance = nullptr, bool destroyed = false)
45 static T* _instance = instance;
46 static bool _destroyed = destroyed;
50 return _instance = nullptr;
54 std::cerr << "Trying to reinstantiate a destroyed singleton, this must not happen!\n";
55 abort(); // This produces a backtrace, which is highly useful for finding the culprit
57 if (_instance != instance) {
58 std::cerr << "Trying to reinstantiate a singleton that is already instantiated, this must not happen!\n";
63 std::cerr << "Trying to access a singleton that has not been instantiated yet!\n";
72 * Mixin class for "pseudo" singletons.
74 * Classes inheriting from this mixin become "pseudo" singletons that can still be constructed
75 * and destroyed in a controlled manner, but also gain an instance() method for static access.
76 * This is very similar to the behavior of e.g. QCoreApplication.
78 * The mixin protects against multiple instantiation, use-before-instantiation and use-after-destruction
79 * by aborting the program. This is intended to find lifetime issues during development; abort()
80 * produces a backtrace that makes it easy to find the culprit.
82 * The Curiously Recurring Template Pattern (CRTP) is used for the mixin to be able to provide a
83 * correctly typed instance pointer.
90 * Constructs the mixin.
92 * The constructor can only be called once; subsequent invocations abort the program.
94 * @param instance Pointer to the instance being created, i.e. the 'this' pointer of the parent class
96 Singleton(T* instance)
98 detail::getOrSetInstance<T>(instance);
101 // Satisfy Rule of Five
102 Singleton(const Singleton&) = delete;
103 Singleton(Singleton&&) = delete;
104 Singleton& operator=(const Singleton&) = delete;
105 Singleton& operator=(Singleton&&) = delete;
110 * Sets the instance pointer to null and flags the destruction, so a subsequent reinstantiation will fail.
114 detail::getOrSetInstance<T>(nullptr, true);
118 * Accesses the instance pointer.
120 * If the singleton hasn't been instantiated yet, the program is aborted. No lazy instantiation takes place,
121 * because the singleton's lifetime shall be explicitly controlled.
123 * @returns A pointer to the instance
127 return detail::getOrSetInstance<T>();