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