MyGUI 3.4.1
MyGUI_Singleton.h
Go to the documentation of this file.
1/*
2 * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3 * Distributed under the MIT License
4 * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5 */
6
7#ifndef MYGUI_SINGLETON_H_
8#define MYGUI_SINGLETON_H_
9
10#include "MyGUI_Diagnostic.h"
11
12namespace MyGUI
13{
14
15#if MYGUI_COMPILER == MYGUI_COMPILER_MSVC
16 template <class T>
17 class Singleton
18#else
19 template <class T>
20 class MYGUI_EXPORT MYGUI_OBSOLETE("Singleton class is deprecated. Do not use singletons.") Singleton
21#endif
22 {
23 public:
24
25 #if defined(__clang__)
26 // This constructor is called before the `T` object is fully constructed, and
27 // pointers are not dereferenced anyway, so UBSan shouldn't check vptrs.
28 __attribute__((no_sanitize("vptr")))
29 #endif
31 {
32 MYGUI_ASSERT(nullptr == msInstance, "Singleton instance " << getClassTypeName() << " already exsist");
33 msInstance = static_cast<T*>(this);
34 }
35
36 virtual ~Singleton()
37 {
38 if (nullptr == msInstance)
39 MYGUI_LOG(Critical, "Destroying Singleton instance " << getClassTypeName() << " before constructing it.");
40 msInstance = nullptr;
41 }
42
43 static T& getInstance()
44 {
45 MYGUI_ASSERT(nullptr != getInstancePtr(), "Singleton instance " << getClassTypeName() << " was not created");
46 return (*getInstancePtr());
47 }
48
49 static T* getInstancePtr()
50 {
51 return msInstance;
52 }
53
54 static const char* getClassTypeName()
55 {
56 return mClassTypeName;
57 }
58
59 private:
60 static T* msInstance;
61 static const char* mClassTypeName;
62 };
63
64/*
65 // Template Singleton class was replaces with a set of macroses, because there were too many issues with it,
66 // all appearing in different compilers:
67 // - incorrect exporting template class;
68 // - static variables in headers issues;
69 // - explicit specialization/implicit instantiation issues;
70 // - many other related compile errors.
71 // It is possible to move all template definitions into cpp code, but result looked even worse.
72
73 // Usage:
74
75 // in header
76 class MyClass
77 {
78 MYGUI_SINGLETON_DECLARATION(MyClass);
79
80 MyClass()
81 // ...
82 };
83
84 // in cpp
85 MYGUI_SINGLETON_DEFINITION(MyClass);
86
87 MyClass() : mSingletonHolder(this)
88 {
89 // ...
90 }
91*/
92
93 // proxy class to avoid calling initialiseSingleton/shutdownSingleton in constructor/destructor
94 template<class T>
96 {
97 public:
98 SingletonHolder(T* instance) :
99 mInstance(instance)
100 {
101 mInstance->initialiseSingleton();
102 }
104 {
105 mInstance->shutdownSingleton();
106 }
107 private:
108 T* mInstance;
109 };
110
111#define MYGUI_SINGLETON_DECLARATION(ClassName) \
112 private: \
113 friend MyGUI::SingletonHolder<ClassName>; \
114 MyGUI::SingletonHolder<ClassName> mSingletonHolder; \
115 void initialiseSingleton(); \
116 void shutdownSingleton(); \
117 \
118 public: \
119 static ClassName& getInstance(); \
120 static ClassName* getInstancePtr(); \
121 static const char* getClassTypeName()
122
123#define MYGUI_SINGLETON_DEFINITION(ClassName) \
124 static ClassName* ClassName##Instance = nullptr; \
125 static const char* ClassName##ClassTypeName = #ClassName; \
126 \
127 void ClassName::initialiseSingleton() \
128 { \
129 MYGUI_ASSERT(nullptr == ClassName##Instance, "Singleton instance " << getClassTypeName() << " already exsist"); \
130 ClassName##Instance = this; \
131 } \
132 \
133 void ClassName::shutdownSingleton() \
134 { \
135 if (nullptr == ClassName##Instance) \
136 MYGUI_LOG(Critical, "Destroying Singleton instance " << getClassTypeName() << " before constructing it."); \
137 ClassName##Instance = nullptr; \
138 } \
139 \
140 ClassName& ClassName::getInstance() \
141 { \
142 MYGUI_ASSERT(nullptr != getInstancePtr(), "Singleton instance " << getClassTypeName() << " was not created"); \
143 return (*getInstancePtr()); \
144 } \
145 \
146 ClassName* ClassName::getInstancePtr() \
147 { \
148 return ClassName##Instance; \
149 } \
150 \
151 const char* ClassName::getClassTypeName() \
152 { \
153 return ClassName##ClassTypeName; \
154 } \
155 static_assert(true, "require semicolon")
156
157} // namespace MyGUI
158
159#endif // MYGUI_SINGLETON_H_
#define MYGUI_ASSERT(exp, dest)
#define MYGUI_OBSOLETE(text)
#define MYGUI_LOG(level, text)
#define MYGUI_EXPORT
SingletonHolder(T *instance)
static T * getInstancePtr()
static T & getInstance()
static const char * getClassTypeName()
virtual ~Singleton()