I'd like to tell about singleton lifetime tracker I use by myself. The alternative lifetime tracking uses linked list of Lifetime objects insead of dynamic array. Since each singleton has only one Lifetime object, these objects are actually statics and there is no memory reallocation.
This strategy allows to define dependencies between singletons instead of operate with arbitrary longevity numbers.
I have three lifetime policies: the default that pushes the object to the lifetime list, the long lifetime that appends the object to the end, and third one allows to define singleton dependancies.
The code is provided below:
class LifetimeBase
{
protected:
LifetimeBase()
: m_pNext(0), m_InList(false)
{
if (!m_pHeader)
{
atexit(DeleteAll);
}
}
~LifetimeBase() {}
virtual void DeleteInstance() = 0;
public:
LifetimeBase *m_pNext;
bool m_InList;
static LifetimeBase *m_pHeader;
private:
static void DeleteAll()
{
for (LifetimeBase *p = m_pHeader; p; p = p->m_pNext)
{
p->DeleteInstance();
}
}
};
LifetimeBase *LifetimeBase::m_pHeader = 0;
template <class T>
class Lifetime: public LifetimeBase
{
public:
typedef void (*Destructor)();
I'd like to tell about singleton lifetime tracker I use by myself. The alternative lifetime tracking uses linked list of Lifetime objects insead of dynamic array. Since each singleton has only one Lifetime object, these objects are actually statics and there is no memory reallocation.
This strategy allows to define dependencies between singletons instead of operate with arbitrary longevity numbers.
I have three lifetime policies: the default that pushes the object to the lifetime list, the long lifetime that appends the object to the end, and third one allows to define singleton dependancies.
The code is provided below:
class LifetimeBase
{
protected:
LifetimeBase()
: m_pNext(0), m_InList(false)
{
if (!m_pHeader)
{
atexit(DeleteAll);
}
}
~LifetimeBase() {}
virtual void DeleteInstance() = 0;
public:
LifetimeBase *m_pNext;
bool m_InList;
static LifetimeBase *m_pHeader;
private:
static void DeleteAll()
{
for (LifetimeBase *p = m_pHeader; p; p = p->m_pNext)
{
p->DeleteInstance();
}
}
};
LifetimeBase *LifetimeBase::m_pHeader = 0;
template <class T>
class Lifetime: public LifetimeBase
{
public:
typedef void (*Destructor)();
// static void ScheduleDestruction(T*, Destructor d)
// { throw std::logic_error("abstract call"); }
void Init(T *host, Destructor dtor)
{
if (!m_pHost)
{
m_pHost = host;
m_Dtor = dtor;
}
}
static void OnDeadReference()
{ throw std::logic_error("Dead Reference Detected"); }
static Lifetime<T> &Instance()
{
if (!m_pInstance)
{
CreateInstance();
}
return *m_pInstance;
}
~Lifetime() {}
protected:
Lifetime()
: m_pHost(0), m_Dtor(0) {}
static Lifetime<T> *CreateInstance()
{
// ### critical section lock
if (!m_pInstance)
{
enum {alignment = 2*sizeof(size_t), alignMask = alignment - 1};
static char placement[sizeof(Lifetime<T>) + alignment];
char *p = (char *)(size_t(placement + alignMask) & ~alignMask);
m_pInstance = new (p) Lifetime<T>;
}
return m_pInstance;
}
virtual void DeleteInstance()
{
if (m_pHost)
{
m_Dtor();
m_pHost = 0;
}
}
T *m_pHost;
Destructor m_Dtor;
private:
static Lifetime<T> *m_pInstance;
};
template <class T>
Lifetime<T> *Lifetime<T>::m_pInstance = 0;
template <class T>
class DefaultLifetime: public Lifetime<T>
{
public:
static void ScheduleDestruction(T *host, Destructor dtor)
{
// ### critical section
Lifetime<T> < = Lifetime<T>::Instance();
lt.Init(host, dtor);
if (!lt.m_InList)
{
lt.m_pNext = m_pHeader;
m_pHeader = <
lt.m_InList = true;
}
}
};
template <class T>
class LongLifetime: public Lifetime<T>
{
public:
static void ScheduleDestruction(T *host, Destructor dtor)
{
// ### critical section
Lifetime<T> < = Lifetime<T>::Instance();
lt.Init(host, dtor);
if (lt.m_InList)
{
// reschedule
// search in list
LifetimeBase *prev = 0;
for (LifetimeBase *p = m_pHeader;
p; prev = p, p = p->m_pNext)
{
if (p == <)
{
break;
}
}
// remove
if (prev)
{
prev->m_pNext = p->m_pNext;
}
else
{
m_pHeader = p->m_pNext;
}
}
// insert at the end
if (!m_pHeader)
{
m_pHeader = <
}
else
{
LifetimeBase *p = m_pHeader;
while (p->m_pNext) p = p->m_pNext;
p->m_pNext = <
}
lt.m_InList = true;
}
};
template <class TDependant, class TPredominant>
class DependantLifetime: public Lifetime<TDependant>
{
public:
static void ScheduleDestruction(TDependant *host, Destructor dtor)
{
// ### critical section
Lifetime<TDependant> &dependant =
Lifetime<TDependant>::Instance();
Lifetime<TPredominant> &predominant =
Lifetime<TPredominant>::Instance();
dependant.Init(host, dtor);
if (!dependant.m_InList)
{
if (!predominant.m_InList)
{
predominant.m_pNext = m_pHeader;
m_pHeader = &predominant;
predominant.m_InList = true;
}
dependant.m_pNext = m_pHeader;
m_pHeader = &dependant;
dependant.m_InList = true;
}
}
};
A loki-experimental project has been setup for proposed extentions & additions.
http://sourceforge.net/projects/loki-exp/