add lifetime policies to manage singleton lifetime dependencies: FollowIntoDeath and DieOrder. Change SmallObject.h to avoid memory leaks by default

git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@338 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
syntheticpp 2005-11-01 11:11:52 +00:00
parent 698ffbff54
commit a7687a05a1
6 changed files with 271 additions and 99 deletions

View file

@ -18,8 +18,10 @@
namespace Loki namespace Loki
{ {
template<class R> template<class R = void()>
struct Function; struct Function : public Functor<R>
{
};
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Function allows a boost/TR1 like usage of Functor. // Function allows a boost/TR1 like usage of Functor.

View file

@ -1130,7 +1130,7 @@ namespace Loki
// class template Functor // class template Functor
// A generalized functor implementation with value semantics // A generalized functor implementation with value semantics
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename R, class TList = NullType, template <typename R = void, class TList = NullType,
template<class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL> template<class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL>
class Functor class Functor
{ {

View file

@ -22,6 +22,7 @@
#include <cassert> #include <cassert>
#include <cstdlib> #include <cstdlib>
#include <new> #include <new>
#include <vector>
#ifdef _MSC_VER #ifdef _MSC_VER
#define LOKI_C_CALLING_CONVENTION_QUALIFIER __cdecl #define LOKI_C_CALLING_CONVENTION_QUALIFIER __cdecl
@ -36,10 +37,10 @@ namespace Loki
namespace Private namespace Private
{ {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class LifetimeTracker // class LifetimeTracker
// Helper class for SetLongevity // Helper class for SetLongevity
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
class LifetimeTracker class LifetimeTracker
{ {
@ -95,14 +96,15 @@ namespace Loki
Destroyer destroyer_; Destroyer destroyer_;
}; };
void LOKI_C_CALLING_CONVENTION_QUALIFIER AtExitFn(); // declaration needed below void LOKI_C_CALLING_CONVENTION_QUALIFIER AtExitFn(); // declaration needed below
} // namespace Private } // namespace Private
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// function template SetLongevity // function template SetLongevity
// Assigns an object a longevity; ensures ordered destructions of objects // Assigns an object a longevity; ensures ordered destructions of objects
// registered thusly during the exit sequence of the application // registered thusly during the exit sequence of the application
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename T, typename Destroyer> template <typename T, typename Destroyer>
void SetLongevity(T* pDynObject, unsigned int longevity, void SetLongevity(T* pDynObject, unsigned int longevity,
@ -144,12 +146,12 @@ namespace Loki
{ {
SetLongevity<T, typename Private::Deleter<T>::Type>(pDynObject, longevity, d); SetLongevity<T, typename Private::Deleter<T>::Type>(pDynObject, longevity, d);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template CreateUsingNew // class template CreateUsingNew
// Implementation of the CreationPolicy used by SingletonHolder // Implementation of the CreationPolicy used by SingletonHolder
// Creates objects using a straight call to the new operator // Creates objects using a straight call to the new operator
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <class T> struct CreateUsingNew template <class T> struct CreateUsingNew
{ {
@ -160,12 +162,12 @@ namespace Loki
{ delete p; } { delete p; }
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template CreateUsingNew // class template CreateUsingNew
// Implementation of the CreationPolicy used by SingletonHolder // Implementation of the CreationPolicy used by SingletonHolder
// Creates objects using a call to std::malloc, followed by a call to the // Creates objects using a call to std::malloc, followed by a call to the
// placement new operator // placement new operator
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <class T> struct CreateUsingMalloc template <class T> struct CreateUsingMalloc
{ {
@ -183,14 +185,14 @@ namespace Loki
} }
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template CreateStatic // class template CreateStatic
// Implementation of the CreationPolicy used by SingletonHolder // Implementation of the CreationPolicy used by SingletonHolder
// Creates an object in static memory // Creates an object in static memory
// Implementation is slightly nonportable because it uses the MaxAlign trick // Implementation is slightly nonportable because it uses the MaxAlign trick
// (an union of all types to ensure proper memory alignment). This trick is // (an union of all types to ensure proper memory alignment). This trick is
// nonportable in theory but highly portable in practice. // nonportable in theory but highly portable in practice.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <class T> struct CreateStatic template <class T> struct CreateStatic
{ {
@ -231,12 +233,12 @@ namespace Loki
} }
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template DefaultLifetime // class template DefaultLifetime
// Implementation of the LifetimePolicy used by SingletonHolder // Implementation of the LifetimePolicy used by SingletonHolder
// Schedules an object's destruction as per C++ rules // Schedules an object's destruction as per C++ rules
// Forwards to std::atexit // Forwards to std::atexit
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <class T> template <class T>
struct DefaultLifetime struct DefaultLifetime
@ -248,12 +250,12 @@ namespace Loki
{ throw std::logic_error("Dead Reference Detected"); } { throw std::logic_error("Dead Reference Detected"); }
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template PhoenixSingleton // class template PhoenixSingleton
// Implementation of the LifetimePolicy used by SingletonHolder // Implementation of the LifetimePolicy used by SingletonHolder
// Schedules an object's destruction as per C++ rules, and it allows object // Schedules an object's destruction as per C++ rules, and it allows object
// recreation by not throwing an exception from OnDeadReference // recreation by not throwing an exception from OnDeadReference
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <class T> template <class T>
class PhoenixSingleton class PhoenixSingleton
@ -284,19 +286,19 @@ namespace Loki
template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false; template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false;
#endif #endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template DeletableSingleton // class template DeletableSingleton
// Copyright (c) 2004 by Curtis Krauskopf - curtis@decompile.com // Copyright (c) 2004 by Curtis Krauskopf - curtis@decompile.com
// //
// A DeletableSingleton allows the instantiated singleton to be // A DeletableSingleton allows the instantiated singleton to be
// destroyed at any time. The singleton can be reinstantiated at // destroyed at any time. The singleton can be reinstantiated at
// any time, even during program termination. // any time, even during program termination.
// If the singleton exists when the program terminates, it will // If the singleton exists when the program terminates, it will
// be automatically deleted. // be automatically deleted.
// //
// The singleton can be deleted manually: // The singleton can be deleted manually:
// DeletableSingleton<MyClass>::GracefulDelete(); // DeletableSingleton<MyClass>::GracefulDelete();
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <class T> template <class T>
class DeletableSingleton class DeletableSingleton
@ -353,10 +355,10 @@ namespace Loki
template <class T> template <class T>
bool DeletableSingleton<T>::needCallback = true; bool DeletableSingleton<T>::needCallback = true;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template Adapter // class template Adapter
// Helper for SingletonWithLongevity below // Helper for SingletonWithLongevity below
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
namespace Private namespace Private
{ {
@ -368,13 +370,13 @@ namespace Loki
}; };
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template SingletonWithLongevity // class template SingletonWithLongevity
// Implementation of the LifetimePolicy used by SingletonHolder // Implementation of the LifetimePolicy used by SingletonHolder
// Schedules an object's destruction in order of their longevities // Schedules an object's destruction in order of their longevities
// Assumes a visible function GetLongevity(T*) that returns the longevity of the // Assumes a visible function GetLongevity(T*) that returns the longevity of the
// object // object
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <class T> template <class T>
class SingletonWithLongevity class SingletonWithLongevity
@ -390,11 +392,11 @@ namespace Loki
{ throw std::logic_error("Dead Reference Detected"); } { throw std::logic_error("Dead Reference Detected"); }
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template NoDestroy // class template NoDestroy
// Implementation of the LifetimePolicy used by SingletonHolder // Implementation of the LifetimePolicy used by SingletonHolder
// Never destroys the object // Never destroys the object
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <class T> template <class T>
struct NoDestroy struct NoDestroy
@ -406,12 +408,149 @@ namespace Loki
{} {}
}; };
////////////////////////////////////////////////////////////////////////////////
// class template SingletonHolder ////////////////////////////////////////////////////////////////////////////////
// Provides Singleton amenities for a type T // DieOrder lifetime policy:
// To protect that type from spurious instantiations, you have to protect it // Policy to handle lifetime dependencies
// yourself. ////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
template <unsigned int Longevity, class T>
class SingletonFixedLongevity
{
public:
static void ScheduleDestruction(T* pObj, atexit_pfn_t pFun)
{
Private::Adapter<T> adapter = { pFun };
SetLongevity(pObj, Longevity , adapter);
}
static void OnDeadReference()
{ throw std::logic_error("Dead Reference Detected"); }
};
struct DieOrder
{
template <class T>
struct Last : public SingletonFixedLongevity<0xFFFFFFFF ,T>
{};
template <class T>
struct First : public SingletonFixedLongevity<0xFFFFFFFF-1,T>
{};
};
////////////////////////////////////////////////////////////////////////////////
// FollowIntoDeath lifetime policy: followers will die after the master dies
// Followers will not die, if
// - master never dies (NoDestroy policy)
// - master never created
// - master dies not in the function registered with atexit
// - master dies not by a call of a the atexit registerd function
// (DeletableSingleton::GreathFullDeath)
//
// Usage:
// Lifetime of the master singleton e.g. with a Master class:
// SingletonHolder<Master,
// FollowIntoDeath::With<DefaultLifetime>::AsMasterLifetime>
// MasterSingleton;
//
// Lifetime of the follower singleton e.g. with a Follower class:
// SingletonHolder<Follower,CreateUsingNew,
// FollowIntoDeath::AfterMaster<MasterSingleton>::IsDestroyed>
// FollowerSingleton
////////////////////////////////////////////////////////////////////////////////
struct FollowIntoDeath
{
template<class T>
class Followers
{
typedef std::vector<atexit_pfn_t> Container;
typedef typename Container::iterator iterator;
static Container* followers_;
public:
static void Init()
{
static bool done = false;
if(!done)
{
followers_ = new Container;
done = true;
}
}
static void AddFollower(atexit_pfn_t ae)
{
Init();
followers_->push_back(ae);
}
static void DestroyFollowers()
{
Init();
for(iterator it = followers_->begin();it != followers_->end();++it)
(*it)();
delete followers_;
}
};
template<template <class> class Lifetime>
struct With
{
template<class Master>
struct AsMasterLifetime
{
static void ScheduleDestruction(Master* pObj, atexit_pfn_t pFun)
{
Followers<Master>::Init();
Lifetime<Master>::ScheduleDestruction(pObj, pFun);
// use same policy for the followers and force a new
// template instantiation, this adds a additional atexit entry
// does not work with SetLonlevity, but there you can control
// the lifetime with the GetLongevity function.
Lifetime<Followers<Master> >::ScheduleDestruction(0,Followers<Master>::DestroyFollowers);
}
static void OnDeadReference()
{
throw std::logic_error("Dead Reference Detected");
}
};
};
template<class Master>
struct AfterMaster
{
template<class F>
struct IsDestroyed
{
static void ScheduleDestruction(F* pObj, atexit_pfn_t pFun)
{
Followers<Master>::AddFollower(pFun);
}
static void OnDeadReference()
{
throw std::logic_error("Dead Reference Detected");
}
};
};
};
template<class T>
typename FollowIntoDeath::Followers<T>::Container*
FollowIntoDeath::Followers<T>::followers_ = 0;
////////////////////////////////////////////////////////////////////////////////
// class template SingletonHolder
// Provides Singleton amenities for a type T
// To protect that type from spurious instantiations, you have to protect it
// yourself.
////////////////////////////////////////////////////////////////////////////////
template template
< <
@ -439,9 +578,9 @@ namespace Loki
static bool destroyed_; static bool destroyed_;
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// SingletonHolder's data // SingletonHolder's data
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template template
< <
@ -462,9 +601,9 @@ namespace Loki
> >
bool SingletonHolder<T, C, L, M>::destroyed_; bool SingletonHolder<T, C, L, M>::destroyed_;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// SingletonHolder::Instance // SingletonHolder::Instance
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template template
< <
@ -483,9 +622,9 @@ namespace Loki
return *pInstance_; return *pInstance_;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// SingletonHolder::MakeInstance (helper for Instance) // SingletonHolder::MakeInstance (helper for Instance)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template template
< <

View file

@ -36,6 +36,15 @@
#define LOKI_DEFAULT_OBJECT_ALIGNMENT 4 #define LOKI_DEFAULT_OBJECT_ALIGNMENT 4
#endif #endif
//#define LOKI_DEFAULT_SMALLOBJ_LIFETIME NoDestroy
//#define LOKI_DEFAULT_SMALLOBJ_LIFETIME DefaultLifetime
#ifndef LOKI_DEFAULT_SMALLOBJ_LIFETIME
#define LOKI_DEFAULT_SMALLOBJ_LIFETIME \
FollowIntoDeath::With<DefaultLifetime>::AsMasterLifetime
#endif
#if defined(LOKI_SMALL_OBJECT_USE_NEW_ARRAY) && defined(_MSC_VER) #if defined(LOKI_SMALL_OBJECT_USE_NEW_ARRAY) && defined(_MSC_VER)
#pragma message("Don't define LOKI_SMALL_OBJECT_USE_NEW_ARRAY when using a Microsoft compiler to prevet memory leaks.") #pragma message("Don't define LOKI_SMALL_OBJECT_USE_NEW_ARRAY when using a Microsoft compiler to prevet memory leaks.")
#pragma message("now calling '#undef LOKI_SMALL_OBJECT_USE_NEW_ARRAY'") #pragma message("now calling '#undef LOKI_SMALL_OBJECT_USE_NEW_ARRAY'")
@ -172,7 +181,7 @@ namespace Loki
std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE, std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE,
std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE, std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE,
std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT, std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT,
template <class> class LifetimePolicy = Loki::NoDestroy template <class> class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME
> >
class AllocatorSingleton : public SmallObjAllocator class AllocatorSingleton : public SmallObjAllocator
{ {
@ -314,16 +323,19 @@ namespace Loki
#if (LOKI_MAX_SMALL_OBJECT_SIZE != 0) && (LOKI_DEFAULT_CHUNK_SIZE != 0) && (LOKI_DEFAULT_OBJECT_ALIGNMENT != 0) #if (LOKI_MAX_SMALL_OBJECT_SIZE != 0) && (LOKI_DEFAULT_CHUNK_SIZE != 0) && (LOKI_DEFAULT_OBJECT_ALIGNMENT != 0)
/// Defines type of allocator. public:
/// Defines type of allocator singleton, must be public
/// to handle singleton lifetime dependencies.
typedef AllocatorSingleton< ThreadingModel, chunkSize, typedef AllocatorSingleton< ThreadingModel, chunkSize,
maxSmallObjectSize, objectAlignSize, LifetimePolicy > MyAllocator; maxSmallObjectSize, objectAlignSize, LifetimePolicy > ObjAllocatorSingleton;
private:
/// Defines type for thread-safety locking mechanism. /// Defines type for thread-safety locking mechanism.
typedef ThreadingModel< MyAllocator > MyThreadingModel; typedef ThreadingModel< ObjAllocatorSingleton > MyThreadingModel;
/// Defines singleton made from allocator. /// Use singleton defined in AllocatorSingleton.
typedef Loki::SingletonHolder< MyAllocator, Loki::CreateStatic, typedef typename ObjAllocatorSingleton::MyAllocatorSingleton MyAllocatorSingleton;
LifetimePolicy, ThreadingModel > MyAllocatorSingleton;
public: public:
@ -459,7 +471,7 @@ namespace Loki
std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE, std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE,
std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE, std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE,
std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT, std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT,
template <class> class LifetimePolicy = Loki::NoDestroy template <class> class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME
> >
class SmallObject : public SmallObjectBase< ThreadingModel, chunkSize, class SmallObject : public SmallObjectBase< ThreadingModel, chunkSize,
maxSmallObjectSize, objectAlignSize, LifetimePolicy > maxSmallObjectSize, objectAlignSize, LifetimePolicy >
@ -493,7 +505,7 @@ namespace Loki
std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE, std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE,
std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE, std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE,
std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT, std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT,
template <class> class LifetimePolicy = Loki::NoDestroy template <class> class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME
> >
class SmallValueObject : public SmallObjectBase< ThreadingModel, chunkSize, class SmallValueObject : public SmallObjectBase< ThreadingModel, chunkSize,
maxSmallObjectSize, objectAlignSize, LifetimePolicy > maxSmallObjectSize, objectAlignSize, LifetimePolicy >
@ -513,6 +525,9 @@ namespace Loki
// Nov. 26, 2004: re-implemented by Rich Sposato. // Nov. 26, 2004: re-implemented by Rich Sposato.
// //
// $Log$ // $Log$
// Revision 1.19 2005/11/01 11:11:52 syntheticpp
// add lifetime policies to manage singleton lifetime dependencies: FollowIntoDeath and DieOrder. Change SmallObject.h to avoid memory leaks by default
//
// Revision 1.18 2005/10/30 14:03:23 syntheticpp // Revision 1.18 2005/10/30 14:03:23 syntheticpp
// replace tabs space // replace tabs space
// //

View file

@ -5,7 +5,7 @@ UnitCount=3
Type=1 Type=1
Ver=1 Ver=1
ObjFiles= ObjFiles=
Includes=..\..\include;..;. Includes=..\..\include;..;.;c:\sandbox\boost_1_33_0
Libs= Libs=
PrivateResource= PrivateResource=
ResourceIncludes= ResourceIncludes=

View file

@ -29,3 +29,19 @@ link /NOLOGO /SUBSYSTEM:CONSOLE /incremental:no /OUT:"Phoenix-msvc.exe" ..\..\li
link /NOLOGO /SUBSYSTEM:CONSOLE /incremental:no /OUT:"Phoenix-msvc.exe" tmp\Phoenix.obj ..\..\lib\SmallObj.obj ..\..\lib\Singleton.obj link /NOLOGO /SUBSYSTEM:CONSOLE /incremental:no /OUT:"Phoenix-msvc.exe" tmp\Phoenix.obj ..\..\lib\SmallObj.obj ..\..\lib\Singleton.obj
) )
:: Dependencies.cpp
cl -c -Zm200 -O2 -DNDEBUG -MT -EHsc -GR -W0 -wd4710 -I"." -I"..\..\include" -Fotmp\ Dependencies.cpp
if not defined LOKI_MSVC_NOLIB (
link /NOLOGO /SUBSYSTEM:CONSOLE /incremental:no /OUT:"Dependencies-msvc.exe" ..\..\lib\loki.lib tmp\Phoenix.obj
) else (
link /NOLOGO /SUBSYSTEM:CONSOLE /incremental:no /OUT:"Dependencies-msvc.exe" tmp\Dependencies.obj ..\..\lib\SmallObj.obj ..\..\lib\Singleton.obj
)