📄 singleton.h
字号:
////////////////////////////////////////////////////////////////////////////////// The Loki Library// Copyright (c) 2001 by Andrei Alexandrescu// This code accompanies the book:// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design // Patterns Applied". Copyright (c) 2001. Addison-Wesley.// Permission to use, copy, modify, distribute and sell this software for any // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation.// The author or Addison-Wesley Longman make no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty.////////////////////////////////////////////////////////////////////////////////#ifndef LOKI_SINGLETON_INC_#define LOKI_SINGLETON_INC_// $Id: Singleton.h 834 2007-08-02 19:36:10Z syntheticpp $#include "LokiExport.h"#include "Threads.h"#include <algorithm>#include <stdexcept>#include <cassert>#include <cstdlib>#include <new>#include <vector>#include <list>#include <memory>#ifdef _MSC_VER#define LOKI_C_CALLING_CONVENTION_QUALIFIER __cdecl #else#define LOKI_C_CALLING_CONVENTION_QUALIFIER #endif/// \defgroup SingletonGroup Singleton/// \defgroup CreationGroup Creation policies/// \ingroup SingletonGroup/// \defgroup LifetimeGroup Lifetime policies/// \ingroup SingletonGroup/// The lifetimes of the singleton./// \par Special lifetime for SmallObjects/// When the holded object is a Small(Value)Object or the holded object /// uses objects which are or inherit from Small(Value)Object/// then you can't use the default lifetime: you must use the lifetime/// \code Loki::LongevityLifetime::DieAsSmallObjectChild \endcode/// Be aware of this when you use Loki::Factory, Loki::Functor, or Loki::Function.namespace Loki{ typedef void (LOKI_C_CALLING_CONVENTION_QUALIFIER *atexit_pfn_t)(); namespace Private {#ifndef LOKI_MAKE_DLL void LOKI_C_CALLING_CONVENTION_QUALIFIER AtExitFn(); // declaration needed below #else void LOKI_EXPORT AtExitFn();#endif class LifetimeTracker;#define LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL #ifdef LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL // Helper data // std::list because of the inserts typedef std::list<LifetimeTracker*> TrackerArray; extern LOKI_EXPORT TrackerArray* pTrackerArray;#else // Helper data typedef LifetimeTracker** TrackerArray; extern TrackerArray pTrackerArray; extern unsigned int elements;#endif //////////////////////////////////////////////////////////////////////////////// // class LifetimeTracker // Helper class for SetLongevity //////////////////////////////////////////////////////////////////////////////// class LifetimeTracker { public: LifetimeTracker(unsigned int x) : longevity_(x) {} virtual ~LifetimeTracker() = 0; static bool Compare(const LifetimeTracker* lhs, const LifetimeTracker* rhs) { return lhs->longevity_ > rhs->longevity_; } private: unsigned int longevity_; }; // Definition required inline LifetimeTracker::~LifetimeTracker() {} // Helper destroyer function template <typename T> struct Deleter { typedef void (*Type)(T*); static void Delete(T* pObj) { delete pObj; } }; // Concrete lifetime tracker for objects of type T template <typename T, typename Destroyer> class ConcreteLifetimeTracker : public LifetimeTracker { public: ConcreteLifetimeTracker(T* p,unsigned int longevity, Destroyer d) : LifetimeTracker(longevity) , pTracked_(p) , destroyer_(d) {} ~ConcreteLifetimeTracker() { destroyer_(pTracked_); } private: T* pTracked_; Destroyer destroyer_; }; } // namespace Private //////////////////////////////////////////////////////////////////////////////// /// \ingroup LifetimeGroup /// /// Assigns an object a longevity; ensures ordered destructions of objects /// registered thusly during the exit sequence of the application ////////////////////////////////////////////////////////////////////////////////#ifdef LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL template <typename T, typename Destroyer> void SetLongevity(T* pDynObject, unsigned int longevity, Destroyer d) { using namespace Private; // manage lifetime of stack manually if(pTrackerArray==0) pTrackerArray = new TrackerArray; // automatically delete the ConcreteLifetimeTracker object when a exception is thrown std::auto_ptr<LifetimeTracker> p( new ConcreteLifetimeTracker<T, Destroyer>(pDynObject, longevity, d) ); // Find correct position TrackerArray::iterator pos = std::upper_bound( pTrackerArray->begin(), pTrackerArray->end(), p.get(), LifetimeTracker::Compare); // Insert the pointer to the ConcreteLifetimeTracker object into the queue pTrackerArray->insert(pos, p.get()); // nothing has thrown: don't delete the ConcreteLifetimeTracker object p.release(); // Register a call to AtExitFn std::atexit(Private::AtExitFn); }#else template <typename T, typename Destroyer> void SetLongevity(T* pDynObject, unsigned int longevity, Destroyer d) { using namespace Private; TrackerArray pNewArray = static_cast<TrackerArray>( std::realloc(pTrackerArray, sizeof(*pTrackerArray) * (elements + 1))); if (!pNewArray) throw std::bad_alloc(); // Delayed assignment for exception safety pTrackerArray = pNewArray; LifetimeTracker* p = new ConcreteLifetimeTracker<T, Destroyer>( pDynObject, longevity, d); // Insert a pointer to the object into the queue TrackerArray pos = std::upper_bound( pTrackerArray, pTrackerArray + elements, p, LifetimeTracker::Compare); std::copy_backward( pos, pTrackerArray + elements, pTrackerArray + elements + 1); *pos = p; ++elements; // Register a call to AtExitFn std::atexit(Private::AtExitFn); }#endif template <typename T> void SetLongevity(T* pDynObject, unsigned int longevity, typename Private::Deleter<T>::Type d = Private::Deleter<T>::Delete) { SetLongevity<T, typename Private::Deleter<T>::Type>(pDynObject, longevity, d); } //////////////////////////////////////////////////////////////////////////////// /// \struct CreateUsingNew /// /// \ingroup CreationGroup /// Implementation of the CreationPolicy used by SingletonHolder /// Creates objects using a straight call to the new operator //////////////////////////////////////////////////////////////////////////////// template <class T> struct CreateUsingNew { static T* Create() { return new T; } static void Destroy(T* p) { delete p; } }; //////////////////////////////////////////////////////////////////////////////// /// \struct CreateUsing /// /// \ingroup CreationGroup /// Implementation of the CreationPolicy used by SingletonHolder /// Creates objects using a custom allocater. /// Usage: e.g. CreateUsing<std::allocator>::Allocator //////////////////////////////////////////////////////////////////////////////// template<template<class> class Alloc> struct CreateUsing { template <class T> struct Allocator { static Alloc<T> allocator; static T* Create() { return new (allocator.allocate(1)) T; } static void Destroy(T* p) { //allocator.destroy(p); p->~T(); allocator.deallocate(p,1); } }; }; //////////////////////////////////////////////////////////////////////////////// /// \struct CreateUsingMalloc /// /// \ingroup CreationGroup /// Implementation of the CreationPolicy used by SingletonHolder /// Creates objects using a call to std::malloc, followed by a call to the /// placement new operator //////////////////////////////////////////////////////////////////////////////// template <class T> struct CreateUsingMalloc { static T* Create() { void* p = std::malloc(sizeof(T)); if (!p) return 0; return new(p) T; } static void Destroy(T* p) { p->~T(); std::free(p); } }; //////////////////////////////////////////////////////////////////////////////// /// \struct CreateStatic /// /// \ingroup CreationGroup /// Implementation of the CreationPolicy used by SingletonHolder /// Creates an object in static memory /// Implementation is slightly nonportable because it uses the MaxAlign trick /// (an union of all types to ensure proper memory alignment). This trick is /// nonportable in theory but highly portable in practice. //////////////////////////////////////////////////////////////////////////////// template <class T> struct CreateStatic { #ifdef _MSC_VER#pragma warning( push ) #pragma warning( disable : 4121 )// alignment of a member was sensitive to packing#endif // _MSC_VER union MaxAlign { char t_[sizeof(T)]; short int shortInt_; int int_; long int longInt_; float float_; double double_; long double longDouble_; struct Test; int Test::* pMember_; int (Test::*pMemberFn_)(int); }; #ifdef _MSC_VER#pragma warning( pop )#endif // _MSC_VER static T* Create() { static MaxAlign staticMemory_; return new(&staticMemory_) T; } static void Destroy(T* p) { p->~T(); } }; //////////////////////////////////////////////////////////////////////////////// /// \struct DefaultLifetime /// /// \ingroup LifetimeGroup /// Implementation of the LifetimePolicy used by SingletonHolder /// Schedules an object's destruction as per C++ rules /// Forwards to std::atexit //////////////////////////////////////////////////////////////////////////////// template <class T> struct DefaultLifetime { static void ScheduleDestruction(T*, atexit_pfn_t pFun) { std::atexit(pFun); } static void OnDeadReference() { throw std::logic_error("Dead Reference Detected"); } }; //////////////////////////////////////////////////////////////////////////////// /// \struct PhoenixSingleton /// /// \ingroup LifetimeGroup /// Implementation of the LifetimePolicy used by SingletonHolder /// Schedules an object's destruction as per C++ rules, and it allows object /// recreation by not throwing an exception from OnDeadReference //////////////////////////////////////////////////////////////////////////////// template <class T> class PhoenixSingleton { public: static void ScheduleDestruction(T*, atexit_pfn_t pFun) {#ifndef ATEXIT_FIXED if (!destroyedOnce_)#endif std::atexit(pFun); } static void OnDeadReference() {#ifndef ATEXIT_FIXED destroyedOnce_ = true;#endif } private:#ifndef ATEXIT_FIXED static bool destroyedOnce_;#endif }; #ifndef ATEXIT_FIXED template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false;#endif //////////////////////////////////////////////////////////////////////////////// // Copyright (c) 2004 by Curtis Krauskopf - curtis@decompile.com /// /// \struct DeletableSingleton /// /// \ingroup LifetimeGroup /// /// A DeletableSingleton allows the instantiated singleton to be /// destroyed at any time. The singleton can be reinstantiated at /// any time, even during program termination. /// If the singleton exists when the program terminates, it will /// be automatically deleted. /// /// \par Usage: /// The singleton can be deleted manually: /// /// DeletableSingleton<MyClass>::GracefulDelete(); //////////////////////////////////////////////////////////////////////////////// template <class T> class DeletableSingleton { public: static void ScheduleDestruction(T*, atexit_pfn_t pFun) { static bool firstPass = true; isDead = false; deleter = pFun; if (firstPass || needCallback) { std::atexit(atexitCallback); firstPass = false; needCallback = false; } } static void OnDeadReference() { } /// delete singleton object manually static void GracefulDelete() { if (isDead) return; isDead = true; deleter(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -