#pragma once #include "../acl_cpp_define.hpp" #include #include "noncopyable.hpp" // singleton.hpp // // Copyright David Abrahams 2006. Original version // // Copyright Robert Ramey 2007. Changes made to permit // application throughout the serialization library. // // 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. namespace acl { #if defined(_WIN32) || defined(_WIN64) # pragma warning(push) # pragma warning(disable : 4511 4512) #endif ////////////////////////////////////////////////////////////////////// // 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 guarenteed 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 entereed. This any // attempt to retieve a mutable instances while locked will // generate a assertion if compiled for debug. class singleton_module : public noncopyable { public: static void lock() { get_lock() = true; } static void unlock() { get_lock() = false; } static bool is_locked() { return get_lock(); } private: static bool& get_lock() { static bool lock_ = false; return lock_; } }; template class singleton_wrapper : public T { public: static bool destroyed_; ~singleton_wrapper() { destroyed_ = true; } }; template bool singleton_wrapper< T >::destroyed_ = false; /** * 单例模板类,用VC2010或GCC编译时,单例对象在 main 函数之前被执行, * 所以它是线程安全的;但在 VC2003 编译成 release 版本时且打开了优化 * 开关,则有可能是线程不安全的,此时不能保证单例对象的构造函数在 * main 之前执行. * 使用举例如下: * class singleton_test : public acl::singleton * { * public: * singleton_test() {} * ~singleton_test() {} * singleton_test& init() { return *this; } * }; * int main() * { * singleton_test& test = singleton_test::get_instance(); * test.init(); * ... * return 0; * } */ template class singleton : public singleton_module { public: static T& get_instance() { static singleton_wrapper< T > t; // refer to instance, causing it to be instantiated (and // initialized at startup on working compilers) assert(!singleton_wrapper< T >::destroyed_); use(instance_); return static_cast(t); } static bool is_destroyed() { return singleton_wrapper< T >::destroyed_; } private: static T& instance_; // include this to provoke instantiation at pre-execution time static void use(T const &) {} }; template T& singleton< T >::instance_ = singleton< T >::get_instance(); ////////////////////////////////////////////////////////////////////////// /** * 上面的实现在 VC2003 的 release 编译时如果打开了优化开关,则不能保证单例 * 的构造函数先于 main 执行,如果是在 VC2003 下编译单例程序且在多个线程下 * 都用单例对象时,建议使用如下的单例模板类,示例如下: * class singleton_test * { * public: * singleton_test() {} * ~singleton_test() {} * singleton_test& init() { return *this; } * }; * int main() * { * singleton_test& test = acl::singleton2::get_instance(); * test.init(); * ... * return 0; * } * */ template struct singleton2 { private: struct object_creator { object_creator() { singleton2::get_instance(); } inline void do_nothing() const {}; }; static object_creator create_object; public: typedef T object_type; static object_type & get_instance() { static object_type obj; create_object.do_nothing(); return obj; } }; template typename singleton2::object_creator singleton2::create_object; #if defined(_WIN32) || defined(_WIN64) #pragma warning(pop) #endif } // namespace acl