S
stevewilliams2004
I am attempting to create a singleton, and was wondering if someone
could give me a sanity check on the design - does it accomplish my
constraints, and/or am I over complicating things. My design
constraints/environment are as follows:
1) Everything is single-threaded during static initialization (as in
prior to the open brace of main)
2) The environment may be multi-threaded during nominal program
execution (within {} of main)
3) I want a guaranteed destructor call to the singleton (excluding
exceptions, or other abnormal circumstances).
4) Other static (and/or) global objects may access the singleton
during their destructors.
The real kicker I was working to accommodate for above is #4. The
Idea I had was to basically hand out reference-counted containers for
the singleton. The tricky part was giving the guarantee that static/
global objects could reference the singleton in their destructors.
The idea was that even after {} main exits, the reference count is
reduced to zero and the singleton is destroyed, but some object's
destructor could still ressurect the singleton by asking for an
instance (which would presumably be destroyed again shortly after the
local use of that reference was destroyed). I tried to minimize the
code as much as possible, sorry in advance it being 117 lines...
//Header
#include <iostream>
using namespace std;
#ifndef SINGLETON_H_
#define SINGLETON_H_
void _Lock();
void _Unlock();
class Singleton;
class SingletonReference {
friend class Singleton;
public:
virtual ~SingletonReference();
SingletonReference(const SingletonReference &source);
Singleton& Get();
protected:
SingletonReference(Singleton **ppInstance);
private:
Singleton *m_pInstance;
};
class Singleton {
friend class SingletonReference;
public:
static SingletonReference Instance();
virtual ~Singleton() {}
void DoSomething();
protected:
Singleton() {}
private:
static Singleton* AddReference();
static void RemoveReference();
Singleton(const Singleton&) {}
static Singleton* s_pInstance;
static size_t s_count;
static SingletonReference s_instance; //Optional, keep-alive to
avoid lots of destroy/realloc
}; //class Singleton
#endif //SINGLETON_H_
//Implementation
//static
Singleton* Singleton::s_pInstance = NULL;
size_t Singleton::s_count = 0;
SingletonReference s_instance = Singleton::Instance();
void _Lock() {
//Some Implementation defined lock*/
}
void _Unlock() {
//Some Implementation defined unlock*/
}
SingletonReference::~SingletonReference() {
Singleton::RemoveReference();
}
SingletonReference::SingletonReference(const SingletonReference
&source)
: m_pInstance(NULL) {
Singleton::AddReference();
m_pInstance = source.m_pInstance;
}
Singleton& SingletonReference::Get() {
return *m_pInstance;
}
SingletonReference::SingletonReference(Singleton **ppInstance)
: m_pInstance(NULL) {
Singleton::AddReference();
m_pInstance = *ppInstance;
}
SingletonReference Singleton::Instance() {
return SingletonReference(&s_pInstance);
}
void Singleton:oSomething() { cout << "Hi" << endl; }
Singleton* Singleton::AddReference() {
_Lock();
if (s_pInstance == NULL) {
s_pInstance = new Singleton();
s_count = 1;
}
else
s_count++;
_Unlock();
return s_pInstance;
}
void Singleton::RemoveReference() {
_Lock();
if (--s_count == 0)
{
delete s_pInstance;
s_pInstance = NULL;
}
_Unlock();
}
could give me a sanity check on the design - does it accomplish my
constraints, and/or am I over complicating things. My design
constraints/environment are as follows:
1) Everything is single-threaded during static initialization (as in
prior to the open brace of main)
2) The environment may be multi-threaded during nominal program
execution (within {} of main)
3) I want a guaranteed destructor call to the singleton (excluding
exceptions, or other abnormal circumstances).
4) Other static (and/or) global objects may access the singleton
during their destructors.
The real kicker I was working to accommodate for above is #4. The
Idea I had was to basically hand out reference-counted containers for
the singleton. The tricky part was giving the guarantee that static/
global objects could reference the singleton in their destructors.
The idea was that even after {} main exits, the reference count is
reduced to zero and the singleton is destroyed, but some object's
destructor could still ressurect the singleton by asking for an
instance (which would presumably be destroyed again shortly after the
local use of that reference was destroyed). I tried to minimize the
code as much as possible, sorry in advance it being 117 lines...
//Header
#include <iostream>
using namespace std;
#ifndef SINGLETON_H_
#define SINGLETON_H_
void _Lock();
void _Unlock();
class Singleton;
class SingletonReference {
friend class Singleton;
public:
virtual ~SingletonReference();
SingletonReference(const SingletonReference &source);
Singleton& Get();
protected:
SingletonReference(Singleton **ppInstance);
private:
Singleton *m_pInstance;
};
class Singleton {
friend class SingletonReference;
public:
static SingletonReference Instance();
virtual ~Singleton() {}
void DoSomething();
protected:
Singleton() {}
private:
static Singleton* AddReference();
static void RemoveReference();
Singleton(const Singleton&) {}
static Singleton* s_pInstance;
static size_t s_count;
static SingletonReference s_instance; //Optional, keep-alive to
avoid lots of destroy/realloc
}; //class Singleton
#endif //SINGLETON_H_
//Implementation
//static
Singleton* Singleton::s_pInstance = NULL;
size_t Singleton::s_count = 0;
SingletonReference s_instance = Singleton::Instance();
void _Lock() {
//Some Implementation defined lock*/
}
void _Unlock() {
//Some Implementation defined unlock*/
}
SingletonReference::~SingletonReference() {
Singleton::RemoveReference();
}
SingletonReference::SingletonReference(const SingletonReference
&source)
: m_pInstance(NULL) {
Singleton::AddReference();
m_pInstance = source.m_pInstance;
}
Singleton& SingletonReference::Get() {
return *m_pInstance;
}
SingletonReference::SingletonReference(Singleton **ppInstance)
: m_pInstance(NULL) {
Singleton::AddReference();
m_pInstance = *ppInstance;
}
SingletonReference Singleton::Instance() {
return SingletonReference(&s_pInstance);
}
void Singleton:oSomething() { cout << "Hi" << endl; }
Singleton* Singleton::AddReference() {
_Lock();
if (s_pInstance == NULL) {
s_pInstance = new Singleton();
s_count = 1;
}
else
s_count++;
_Unlock();
return s_pInstance;
}
void Singleton::RemoveReference() {
_Lock();
if (--s_count == 0)
{
delete s_pInstance;
s_pInstance = NULL;
}
_Unlock();
}