1 ////////////////////////////////////////////////////////////////////////////////
3 // Copyright (c) 2001 by Andrei Alexandrescu
4 // This code accompanies the book:
5 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
6 // Patterns Applied". Copyright (c) 2001. Addison-Wesley.
7 // Permission to use, copy, modify, distribute and sell this software for any
8 // purpose is hereby granted without fee, provided that the above copyright
9 // notice appear in all copies and that both that copyright notice and this
10 // permission notice appear in supporting documentation.
11 // The author or Addison-Wesley Longman make no representations about the
12 // suitability of this software for any purpose. It is provided "as is"
13 // without express or implied warranty.
14 ////////////////////////////////////////////////////////////////////////////////
15 #ifndef LOKI_SINGLETON_INC_
16 #define LOKI_SINGLETON_INC_
18 // $Id: Singleton.h 834 2007-08-02 19:36:10Z syntheticpp $
21 #include "LokiExport.h"
33 #define LOKI_C_CALLING_CONVENTION_QUALIFIER __cdecl
35 #define LOKI_C_CALLING_CONVENTION_QUALIFIER
38 /// \defgroup SingletonGroup Singleton
39 /// \defgroup CreationGroup Creation policies
40 /// \ingroup SingletonGroup
41 /// \defgroup LifetimeGroup Lifetime policies
42 /// \ingroup SingletonGroup
43 /// The lifetimes of the singleton.
44 /// \par Special lifetime for SmallObjects
45 /// When the holded object is a Small(Value)Object or the holded object
46 /// uses objects which are or inherit from Small(Value)Object
47 /// then you can't use the default lifetime: you must use the lifetime
48 /// \code Loki::LongevityLifetime::DieAsSmallObjectChild \endcode
49 /// Be aware of this when you use Loki::Factory, Loki::Functor, or Loki::Function.
55 typedef void (LOKI_C_CALLING_CONVENTION_QUALIFIER *atexit_pfn_t)();
61 void LOKI_C_CALLING_CONVENTION_QUALIFIER AtExitFn(); // declaration needed below
63 void LOKI_EXPORT AtExitFn();
66 class LifetimeTracker;
68 #define LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL
69 #ifdef LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL
72 // std::list because of the inserts
73 typedef std::list<LifetimeTracker *> TrackerArray;
74 extern LOKI_EXPORT TrackerArray *pTrackerArray;
77 typedef LifetimeTracker **TrackerArray;
78 extern TrackerArray pTrackerArray;
79 extern unsigned int elements;
82 ////////////////////////////////////////////////////////////////////////////////
83 // class LifetimeTracker
84 // Helper class for SetLongevity
85 ////////////////////////////////////////////////////////////////////////////////
90 LifetimeTracker(unsigned int x) : longevity_(x)
93 virtual ~LifetimeTracker() = 0;
95 static bool Compare(const LifetimeTracker *lhs,
96 const LifetimeTracker *rhs)
98 return lhs->longevity_ > rhs->longevity_;
102 unsigned int longevity_;
105 // Definition required
106 inline LifetimeTracker::~LifetimeTracker() {}
108 // Helper destroyer function
109 template <typename T>
112 typedef void (*Type)(T *);
113 static void Delete(T *pObj)
119 // Concrete lifetime tracker for objects of type T
120 template <typename T, typename Destroyer>
121 class ConcreteLifetimeTracker : public LifetimeTracker
124 ConcreteLifetimeTracker(T *p,unsigned int longevity, Destroyer d)
125 : LifetimeTracker(longevity)
130 ~ConcreteLifetimeTracker()
132 destroyer_(pTracked_);
137 Destroyer destroyer_;
140 } // namespace Private
142 ////////////////////////////////////////////////////////////////////////////////
143 /// \ingroup LifetimeGroup
145 /// Assigns an object a longevity; ensures ordered destructions of objects
146 /// registered thusly during the exit sequence of the application
147 ////////////////////////////////////////////////////////////////////////////////
149 #ifdef LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL
151 template <typename T, typename Destroyer>
152 void SetLongevity(T *pDynObject, unsigned int longevity,
155 using namespace Private;
157 // manage lifetime of stack manually
159 pTrackerArray = new TrackerArray;
161 // automatically delete the ConcreteLifetimeTracker object when a exception is thrown
162 std::auto_ptr<LifetimeTracker>
163 p( new ConcreteLifetimeTracker<T, Destroyer>(pDynObject, longevity, d) );
165 // Find correct position
166 TrackerArray::iterator pos = std::upper_bound(
167 pTrackerArray->begin(),
168 pTrackerArray->end(),
170 LifetimeTracker::Compare);
172 // Insert the pointer to the ConcreteLifetimeTracker object into the queue
173 pTrackerArray->insert(pos, p.get());
175 // nothing has thrown: don't delete the ConcreteLifetimeTracker object
178 // Register a call to AtExitFn
179 std::atexit(Private::AtExitFn);
184 template <typename T, typename Destroyer>
185 void SetLongevity(T *pDynObject, unsigned int longevity,
188 using namespace Private;
190 TrackerArray pNewArray = static_cast<TrackerArray>(
191 std::realloc(pTrackerArray,
192 sizeof(*pTrackerArray) * (elements + 1)));
193 if (!pNewArray) throw std::bad_alloc();
195 // Delayed assignment for exception safety
196 pTrackerArray = pNewArray;
198 LifetimeTracker *p = new ConcreteLifetimeTracker<T, Destroyer>(
199 pDynObject, longevity, d);
201 // Insert a pointer to the object into the queue
202 TrackerArray pos = std::upper_bound(
204 pTrackerArray + elements,
206 LifetimeTracker::Compare);
209 pTrackerArray + elements,
210 pTrackerArray + elements + 1);
214 // Register a call to AtExitFn
215 std::atexit(Private::AtExitFn);
220 template <typename T>
221 void SetLongevity(T *pDynObject, unsigned int longevity,
222 typename Private::Deleter<T>::Type d = Private::Deleter<T>::Delete)
224 SetLongevity<T, typename Private::Deleter<T>::Type>(pDynObject, longevity, d);
227 ////////////////////////////////////////////////////////////////////////////////
228 /// \struct CreateUsingNew
230 /// \ingroup CreationGroup
231 /// Implementation of the CreationPolicy used by SingletonHolder
232 /// Creates objects using a straight call to the new operator
233 ////////////////////////////////////////////////////////////////////////////////
234 template <class T> struct CreateUsingNew
241 static void Destroy(T *p)
247 ////////////////////////////////////////////////////////////////////////////////
248 /// \struct CreateUsing
250 /// \ingroup CreationGroup
251 /// Implementation of the CreationPolicy used by SingletonHolder
252 /// Creates objects using a custom allocater.
253 /// Usage: e.g. CreateUsing<std::allocator>::Allocator
254 ////////////////////////////////////////////////////////////////////////////////
255 template<template<class> class Alloc>
261 static Alloc<T> allocator;
265 return new (allocator.allocate(1)) T;
268 static void Destroy(T *p)
270 //allocator.destroy(p);
272 allocator.deallocate(p,1);
277 ////////////////////////////////////////////////////////////////////////////////
278 /// \struct CreateUsingMalloc
280 /// \ingroup CreationGroup
281 /// Implementation of the CreationPolicy used by SingletonHolder
282 /// Creates objects using a call to std::malloc, followed by a call to the
283 /// placement new operator
284 ////////////////////////////////////////////////////////////////////////////////
285 template <class T> struct CreateUsingMalloc
289 void *p = std::malloc(sizeof(T));
294 static void Destroy(T *p)
302 ////////////////////////////////////////////////////////////////////////////////
303 /// \struct CreateStatic
305 /// \ingroup CreationGroup
306 /// Implementation of the CreationPolicy used by SingletonHolder
307 /// Creates an object in static memory
308 /// Implementation is slightly nonportable because it uses the MaxAlign trick
309 /// (an union of all types to ensure proper memory alignment). This trick is
310 /// nonportable in theory but highly portable in practice.
311 ////////////////////////////////////////////////////////////////////////////////
312 template <class T> struct CreateStatic
316 #pragma warning( push )
317 #pragma warning( disable : 4121 )
318 // alignment of a member was sensitive to packing
329 long double longDouble_;
332 int (Test::*pMemberFn_)(int);
336 #pragma warning( pop )
341 static MaxAlign staticMemory_;
342 return new(&staticMemory_) T;
345 static void Destroy(T *p)
351 ////////////////////////////////////////////////////////////////////////////////
352 /// \struct DefaultLifetime
354 /// \ingroup LifetimeGroup
355 /// Implementation of the LifetimePolicy used by SingletonHolder
356 /// Schedules an object's destruction as per C++ rules
357 /// Forwards to std::atexit
358 ////////////////////////////////////////////////////////////////////////////////
360 struct DefaultLifetime
362 static void ScheduleDestruction(T *, atexit_pfn_t pFun)
367 static void OnDeadReference()
369 throw std::logic_error("Dead Reference Detected");
373 ////////////////////////////////////////////////////////////////////////////////
374 /// \struct PhoenixSingleton
376 /// \ingroup LifetimeGroup
377 /// Implementation of the LifetimePolicy used by SingletonHolder
378 /// Schedules an object's destruction as per C++ rules, and it allows object
379 /// recreation by not throwing an exception from OnDeadReference
380 ////////////////////////////////////////////////////////////////////////////////
382 class PhoenixSingleton
385 static void ScheduleDestruction(T *, atexit_pfn_t pFun)
393 static void OnDeadReference()
396 destroyedOnce_ = true;
402 static bool destroyedOnce_;
407 template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false;
410 ////////////////////////////////////////////////////////////////////////////////
411 // Copyright (c) 2004 by Curtis Krauskopf - curtis@decompile.com
413 /// \struct DeletableSingleton
415 /// \ingroup LifetimeGroup
417 /// A DeletableSingleton allows the instantiated singleton to be
418 /// destroyed at any time. The singleton can be reinstantiated at
419 /// any time, even during program termination.
420 /// If the singleton exists when the program terminates, it will
421 /// be automatically deleted.
424 /// The singleton can be deleted manually:
426 /// DeletableSingleton<MyClass>::GracefulDelete();
427 ////////////////////////////////////////////////////////////////////////////////
429 class DeletableSingleton
433 static void ScheduleDestruction(T *, atexit_pfn_t pFun)
435 static bool firstPass = true;
438 if (firstPass || needCallback)
440 std::atexit(atexitCallback);
442 needCallback = false;
446 static void OnDeadReference()
449 /// delete singleton object manually
450 static void GracefulDelete()
459 static atexit_pfn_t deleter;
461 static bool needCallback;
463 static void atexitCallback()
468 needCallback = false;
475 atexit_pfn_t DeletableSingleton<T>::deleter = 0;
478 bool DeletableSingleton<T>::isDead = true;
481 bool DeletableSingleton<T>::needCallback = true;
483 ////////////////////////////////////////////////////////////////////////////////
484 // class template Adapter
485 // Helper for SingletonWithLongevity below
486 ////////////////////////////////////////////////////////////////////////////////
501 ////////////////////////////////////////////////////////////////////////////////
502 /// \struct SingletonWithLongevity
504 /// \ingroup LifetimeGroup
505 /// Implementation of the LifetimePolicy used by SingletonHolder
506 /// Schedules an object's destruction in order of their longevities
507 /// Assumes a visible function GetLongevity(T*) that returns the longevity of the
509 ////////////////////////////////////////////////////////////////////////////////
511 class SingletonWithLongevity
514 static void ScheduleDestruction(T *pObj, atexit_pfn_t pFun)
516 Private::Adapter<T> adapter = { pFun };
517 SetLongevity(pObj, GetLongevity(pObj), adapter);
520 static void OnDeadReference()
522 throw std::logic_error("Dead Reference Detected");
526 ////////////////////////////////////////////////////////////////////////////////
527 /// \struct NoDestroy
529 /// \ingroup LifetimeGroup
530 /// Implementation of the LifetimePolicy used by SingletonHolder
531 /// Never destroys the object
532 ////////////////////////////////////////////////////////////////////////////////
536 static void ScheduleDestruction(T *, atexit_pfn_t)
539 static void OnDeadReference()
544 ////////////////////////////////////////////////////////////////////////////////
545 /// \defgroup LongevityLifetimeGroup LongevityLifetime
546 /// \ingroup LifetimeGroup
548 /// \namespace LongevityLifetime
550 /// \ingroup LongevityLifetimeGroup
551 /// \brief In this namespace are special lifetime policies to manage lifetime
553 ////////////////////////////////////////////////////////////////////////////////
554 namespace LongevityLifetime
556 ////////////////////////////////////////////////////////////////////////////////
557 /// \struct SingletonFixedLongevity
559 /// \ingroup LongevityLifetimeGroup
560 /// Add your own lifetimes into the namespace 'LongevityLifetime'
561 /// with your prefered lifetime by adding a struct like this:
563 /// template<class T>
564 /// struct MyLifetime : SingletonFixedLongevity< MyLifetimeNumber ,T> {}
565 ////////////////////////////////////////////////////////////////////////////////
566 template <unsigned int Longevity, class T>
567 class SingletonFixedLongevity
570 virtual ~SingletonFixedLongevity() {}
572 static void ScheduleDestruction(T *pObj, atexit_pfn_t pFun)
574 Private::Adapter<T> adapter = { pFun };
575 SetLongevity(pObj, Longevity , adapter);
578 static void OnDeadReference()
580 throw std::logic_error("Dead Reference Detected");
585 /// \ingroup LongevityLifetimeGroup
586 /// \brief Longest possible SingletonWithLongevity lifetime: 0xFFFFFFFF
588 struct DieLast : SingletonFixedLongevity<0xFFFFFFFF ,T>
591 /// \struct DieDirectlyBeforeLast
592 /// \ingroup LongevityLifetimeGroup
593 /// \brief Lifetime is a one less than DieLast: 0xFFFFFFFF-1
595 struct DieDirectlyBeforeLast : SingletonFixedLongevity<0xFFFFFFFF-1 ,T>
599 /// \ingroup LongevityLifetimeGroup
600 /// \brief Shortest possible SingletonWithLongevity lifetime: 0
602 struct DieFirst : SingletonFixedLongevity<0,T>
605 }//namespace LongevityLifetime
607 ////////////////////////////////////////////////////////////////////////////////
608 /// \class FollowIntoDeath
610 /// \ingroup LifetimeGroup
612 /// Lifetime policyfor the SingletonHolder tempalte.
613 /// Followers will die after the master dies Followers will not die, if
614 /// - master never dies (NoDestroy policy)
615 /// - master never created
616 /// - master dies not in the function registered with atexit
617 /// - master dies not by a call of a the atexit registerd function (DeletableSingleton::GracefulDelete)
621 /// Lifetimes of the master and the follower singletons, e.g. with a M and a F class:
622 /// \code SingletonHolder< M , FollowIntoDeath::With<DefaultLifetime>::AsMasterLifetime > MasterSingleton; \endcode
623 /// \code SingletonHolder< F , CreateUsingNew, FollowIntoDeath::AfterMaster< MasterSingleton >::IsDestroyed > FollowerSingleton \endcode
624 ////////////////////////////////////////////////////////////////////////////////
625 class FollowIntoDeath
630 typedef std::vector<atexit_pfn_t> Container;
631 typedef typename Container::iterator iterator;
632 static Container *followers_;
637 static bool done = false;
640 followers_ = new Container;
645 static void AddFollower(atexit_pfn_t ae)
648 followers_->push_back(ae);
651 static void DestroyFollowers()
654 for(iterator it = followers_->begin(); it != followers_->end(); ++it)
663 /// Template for the master
664 /// \param Lifetime Lifetime policy for the master
665 template<template <class> class Lifetime>
668 /// \struct AsMasterLifetime
669 /// Policy for master
670 template<class Master>
671 struct AsMasterLifetime
673 static void ScheduleDestruction(Master *pObj, atexit_pfn_t pFun)
675 Followers<Master>::Init();
676 Lifetime<Master>::ScheduleDestruction(pObj, pFun);
678 // use same policy for the followers and force a new
679 // template instantiation, this adds a additional atexit entry
680 // does not work with SetLonlevity, but there you can control
681 // the lifetime with the GetLongevity function.
682 Lifetime<Followers<Master> >::ScheduleDestruction(0,Followers<Master>::DestroyFollowers);
685 static void OnDeadReference()
687 throw std::logic_error("Dead Reference Detected");
692 /// \struct AfterMaster
693 /// Template for the follower
694 /// \param Master Master to follow into death
695 template<class Master>
698 /// \struct IsDestroyed
699 /// Policy for followers
703 static void ScheduleDestruction(F *, atexit_pfn_t pFun)
705 Followers<Master>::AddFollower(pFun);
708 static void OnDeadReference()
710 throw std::logic_error("Dead Reference Detected");
717 typename FollowIntoDeath::Followers<T>::Container *
718 FollowIntoDeath::Followers<T>::followers_ = 0;
722 ////////////////////////////////////////////////////////////////////////////////
723 /// \class SingletonHolder
725 /// \ingroup SingletonGroup
727 /// Provides Singleton amenities for a type T
728 /// To protect that type from spurious instantiations,
729 /// you have to protect it yourself.
731 /// \param CreationPolicy Creation policy, default: CreateUsingNew
732 /// \param LifetimePolicy Lifetime policy, default: DefaultLifetime,
733 /// \param ThreadingModel Threading policy,
734 /// default: LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL
735 ////////////////////////////////////////////////////////////////////////////////
739 template <class> class CreationPolicy = CreateUsingNew,
740 template <class> class LifetimePolicy = DefaultLifetime,
741 template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
742 class MutexPolicy = LOKI_DEFAULT_MUTEX
744 class SingletonHolder
748 /// Type of the singleton object
749 typedef T ObjectType;
751 /// Returns a reference to singleton object
752 static T &Instance();
756 static void MakeInstance();
757 static void LOKI_C_CALLING_CONVENTION_QUALIFIER DestroySingleton();
763 typedef typename ThreadingModel<T *,MutexPolicy>::VolatileType PtrInstanceType;
764 static PtrInstanceType pInstance_;
765 static bool destroyed_;
768 ////////////////////////////////////////////////////////////////////////////////
769 // SingletonHolder's data
770 ////////////////////////////////////////////////////////////////////////////////
775 template <class> class C,
776 template <class> class L,
777 template <class, class> class M,
780 typename SingletonHolder<T, C, L, M, X>::PtrInstanceType
781 SingletonHolder<T, C, L, M, X>::pInstance_ = 0;
786 template <class> class C,
787 template <class> class L,
788 template <class, class> class M,
791 bool SingletonHolder<T, C, L, M, X>::destroyed_ = false;
793 ////////////////////////////////////////////////////////////////////////////////
794 // SingletonHolder::Instance
795 ////////////////////////////////////////////////////////////////////////////////
800 template <class> class CreationPolicy,
801 template <class> class LifetimePolicy,
802 template <class, class> class ThreadingModel,
805 inline T &SingletonHolder<T, CreationPolicy,
806 LifetimePolicy, ThreadingModel, MutexPolicy>::Instance()
815 ////////////////////////////////////////////////////////////////////////////////
816 // SingletonHolder::MakeInstance (helper for Instance)
817 ////////////////////////////////////////////////////////////////////////////////
822 template <class> class CreationPolicy,
823 template <class> class LifetimePolicy,
824 template <class, class> class ThreadingModel,
827 void SingletonHolder<T, CreationPolicy,
828 LifetimePolicy, ThreadingModel, MutexPolicy>::MakeInstance()
830 typename ThreadingModel<SingletonHolder,MutexPolicy>::Lock guard;
838 LifetimePolicy<T>::OnDeadReference();
840 pInstance_ = CreationPolicy<T>::Create();
841 LifetimePolicy<T>::ScheduleDestruction(pInstance_,
849 template <class> class CreationPolicy,
850 template <class> class L,
851 template <class, class> class M,
854 void LOKI_C_CALLING_CONVENTION_QUALIFIER
855 SingletonHolder<T, CreationPolicy, L, M, X>::DestroySingleton()
858 CreationPolicy<T>::Destroy(pInstance_);
864 ////////////////////////////////////////////////////////////////////////////////
867 /// \ingroup SingletonGroup
869 /// Convenience template to implement a getter function for a singleton object.
870 /// Often needed in a shared library which hosts singletons.
874 /// see test/SingletonDll
876 ////////////////////////////////////////////////////////////////////////////////
878 #ifndef LOKI_SINGLETON_EXPORT
879 #define LOKI_SINGLETON_EXPORT
883 class LOKI_SINGLETON_EXPORT Singleton
886 static T &Instance();
892 /// \def LOKI_SINGLETON_INSTANCE_DEFINITION(SHOLDER)
893 /// Convenience macro for the definition of the static Instance member function
894 /// Put this macro called with a SingletonHolder typedef into your cpp file.
896 #define LOKI_SINGLETON_INSTANCE_DEFINITION(SHOLDER) \
900 SHOLDER::ObjectType& Singleton<SHOLDER::ObjectType>::Instance() \
902 return SHOLDER::Instance(); \
907 #endif // end file guardian