singleton.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #ifndef BOOST_SERIALIZATION_SINGLETON_HPP
  2. #define BOOST_SERIALIZATION_SINGLETON_HPP
  3. /////////1/////////2///////// 3/////////4/////////5/////////6/////////7/////////8
  4. // singleton.hpp
  5. //
  6. // Copyright David Abrahams 2006. Original version
  7. //
  8. // Copyright Robert Ramey 2007. Changes made to permit
  9. // application throughout the serialization library.
  10. //
  11. // Copyright Alexander Grund 2018. Corrections to singleton lifetime
  12. //
  13. // Distributed under the Boost
  14. // Software License, Version 1.0. (See accompanying
  15. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  16. //
  17. // The intention here is to define a template which will convert
  18. // any class into a singleton with the following features:
  19. //
  20. // a) initialized before first use.
  21. // b) thread-safe for const access to the class
  22. // c) non-locking
  23. //
  24. // In order to do this,
  25. // a) Initialize dynamically when used.
  26. // b) Require that all singletons be initialized before main
  27. // is called or any entry point into the shared library is invoked.
  28. // This guarentees no race condition for initialization.
  29. // In debug mode, we assert that no non-const functions are called
  30. // after main is invoked.
  31. //
  32. // MS compatible compilers support #pragma once
  33. #if defined(_MSC_VER)
  34. # pragma once
  35. #endif
  36. #include <boost/assert.hpp>
  37. #include <boost/config.hpp>
  38. #include <boost/noncopyable.hpp>
  39. #include <boost/serialization/force_include.hpp>
  40. #include <boost/serialization/config.hpp>
  41. #include <boost/archive/detail/auto_link_archive.hpp>
  42. #include <boost/archive/detail/abi_prefix.hpp> // must be the last header
  43. #ifdef BOOST_MSVC
  44. # pragma warning(push)
  45. # pragma warning(disable : 4511 4512)
  46. #endif
  47. namespace boost {
  48. namespace serialization {
  49. //////////////////////////////////////////////////////////////////////
  50. // Provides a dynamically-initialized (singleton) instance of T in a
  51. // way that avoids LNK1179 on vc6. See http://tinyurl.com/ljdp8 or
  52. // http://lists.boost.org/Archives/boost/2006/05/105286.php for
  53. // details.
  54. //
  55. // Singletons created by this code are guaranteed to be unique
  56. // within the executable or shared library which creates them.
  57. // This is sufficient and in fact ideal for the serialization library.
  58. // The singleton is created when the module is loaded and destroyed
  59. // when the module is unloaded.
  60. // This base class has two functions.
  61. // First it provides a module handle for each singleton indicating
  62. // the executable or shared library in which it was created. This
  63. // turns out to be necessary and sufficient to implement the tables
  64. // used by serialization library.
  65. // Second, it provides a mechanism to detect when a non-const function
  66. // is called after initialization.
  67. // Make a singleton to lock/unlock all singletons for alteration.
  68. // The intent is that all singletons created/used by this code
  69. // are to be initialized before main is called. A test program
  70. // can lock all the singletons when main is entered. Thus any
  71. // attempt to retrieve a mutable instance while locked will
  72. // generate an assertion if compiled for debug.
  73. // The singleton template can be used in 2 ways:
  74. // 1 (Recommended): Publicly inherit your type T from singleton<T>,
  75. // make its ctor protected and access it via T::get_const_instance()
  76. // 2: Simply access singleton<T> without changing T. Note that this only
  77. // provides a global instance accesible by singleton<T>::get_const_instance()
  78. // or singleton<T>::get_mutable_instance() to prevent using multiple instances
  79. // of T make its ctor protected
  80. // Note on usage of BOOST_DLLEXPORT: These functions are in danger of
  81. // being eliminated by the optimizer when building an application in
  82. // release mode. Usage of the macro is meant to signal the compiler/linker
  83. // to avoid dropping these functions which seem to be unreferenced.
  84. // This usage is not related to autolinking.
  85. class BOOST_SYMBOL_VISIBLE singleton_module :
  86. public boost::noncopyable
  87. {
  88. private:
  89. BOOST_DLLEXPORT bool & get_lock() BOOST_USED {
  90. static bool lock = false;
  91. return lock;
  92. }
  93. public:
  94. BOOST_DLLEXPORT void lock(){
  95. get_lock() = true;
  96. }
  97. BOOST_DLLEXPORT void unlock(){
  98. get_lock() = false;
  99. }
  100. BOOST_DLLEXPORT bool is_locked(){
  101. return get_lock();
  102. }
  103. };
  104. static inline singleton_module & get_singleton_module(){
  105. static singleton_module m;
  106. return m;
  107. }
  108. namespace detail {
  109. // This is the class actually instantiated and hence the real singleton.
  110. // So there will only be one instance of this class. This does not hold
  111. // for singleton<T> as a class derived from singleton<T> could be
  112. // instantiated multiple times.
  113. // It also provides a flag `is_destroyed` which returns true, when the
  114. // class was destructed. It is static and hence accesible even after
  115. // destruction. This can be used to check, if the singleton is still
  116. // accesible e.g. in destructors of other singletons.
  117. template<class T>
  118. class singleton_wrapper : public T
  119. {
  120. static bool & get_is_destroyed(){
  121. // Prefer a static function member to avoid LNK1179.
  122. // Note: As this is for a singleton (1 instance only) it must be set
  123. // never be reset (to false)!
  124. static bool is_destroyed_flag = false;
  125. return is_destroyed_flag;
  126. }
  127. public:
  128. singleton_wrapper(){
  129. BOOST_ASSERT(! is_destroyed());
  130. }
  131. ~singleton_wrapper(){
  132. get_is_destroyed() = true;
  133. }
  134. static bool is_destroyed(){
  135. return get_is_destroyed();
  136. }
  137. };
  138. } // detail
  139. template <class T>
  140. class singleton {
  141. private:
  142. static T * m_instance;
  143. // include this to provoke instantiation at pre-execution time
  144. static void use(T const &) {}
  145. static T & get_instance() {
  146. BOOST_ASSERT(! is_destroyed());
  147. // use a wrapper so that types T with protected constructors can be used
  148. // Using a static function member avoids LNK1179
  149. static detail::singleton_wrapper< T > t;
  150. // note that the following is absolutely essential.
  151. // commenting out this statement will cause compilers to fail to
  152. // construct the instance at pre-execution time. This would prevent
  153. // our usage/implementation of "locking" and introduce uncertainty into
  154. // the sequence of object initialization.
  155. // Unfortunately, this triggers detectors of undefine behavior
  156. // and reports an error. But I've been unable to find a different
  157. // of guarenteeing that the the singleton is created at pre-main time.
  158. if (m_instance) use(* m_instance);
  159. return static_cast<T &>(t);
  160. }
  161. protected:
  162. // Do not allow instantiation of a singleton<T>. But we want to allow
  163. // `class T: public singleton<T>` so we can't delete this ctor
  164. BOOST_DLLEXPORT singleton(){}
  165. public:
  166. BOOST_DLLEXPORT static T & get_mutable_instance(){
  167. BOOST_ASSERT(! get_singleton_module().is_locked());
  168. return get_instance();
  169. }
  170. BOOST_DLLEXPORT static const T & get_const_instance(){
  171. return get_instance();
  172. }
  173. BOOST_DLLEXPORT static bool is_destroyed(){
  174. return detail::singleton_wrapper< T >::is_destroyed();
  175. }
  176. };
  177. // Assigning the instance reference to a static member forces initialization
  178. // at startup time as described in
  179. // https://groups.google.com/forum/#!topic/microsoft.public.vc.language/kDVNLnIsfZk
  180. template<class T>
  181. T * singleton< T >::m_instance = & singleton< T >::get_instance();
  182. } // namespace serialization
  183. } // namespace boost
  184. #include <boost/archive/detail/abi_suffix.hpp> // pops abi_suffix.hpp pragmas
  185. #ifdef BOOST_MSVC
  186. #pragma warning(pop)
  187. #endif
  188. #endif // BOOST_SERIALIZATION_SINGLETON_HPP