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 
12 namespace 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 const char * getClassTypeName()
static T * getInstancePtr()
static T & getInstance()
virtual ~Singleton()