|
Boost : |
From: Gregory Dai (gregory.dai_at_[hidden])
Date: 2007-05-08 23:13:02
On 5/8/07, Medland, Thomas M <thomas.medland_at_[hidden]> wrote:
>
>
> Hi,
>
> I have just moved company and in my old company I used to use a
> RogueWave singleton class. I was looking to use the boost singleton
> class. However after looking at the implementation I saw there was no
> private default copy constructor or assignment operator. Does this not
> mean that I could create multiple instances of my singleton via
> assignment or some other form of copying? I saw some discussion of a
> better singleton representation in boost and I was wondering what the
> status of this was, and I was also wondering what other people use for
> their singletons?
>
> Thanks
> Tom
Well, I use the following. It's pretty simple and it works.
#ifndef STE_PATTERN_SINGLETON_HPP
#define STE_PATTERN_SINGLETON_HPP
#include <memory>
#include <boost/noncopyable.hpp>
#include <boost/thread/mutex.hpp>
namespace ste {
namespace pattern {
//+--------------------------------------------------------------------------------------+
//| instantiation policies, etc.
class static_instantiation
{
template <typename T>
class holder
{
friend class static_instantiation;
static T instance_s;
};
protected:
template <typename T>
static void make(T*& p)
{
p = &holder<T>::instance_s;
}
};
template <typename T>
T static_instantiation::holder<T>::instance_s;
class local_static_instantiation
{
protected:
template <typename T>
static void make(T*& p)
{
static T instance;
p = &instance;
}
};
//| basically auto_ptr<T>, which is too common to be made a friend of T for
the purpose.
template <typename T>
class singleton_destroyer : private boost::noncopyable
{
friend class lazy_instantiation;
explicit singleton_destroyer(T* p) : p_(p) {}
~singleton_destroyer() { try { if (p_) delete p_, p_=0; } catch (...) {}
}
T* p_;
};
class lazy_instantiation
{
protected:
template <typename T>
static void make(T*& p)
{
static singleton_destroyer<T> sd(p = new T());
}
};
//+--------------------------------------------------------------------------------------+
//| rules of application:
//| first, declare/make both the default (and only) ctor and the dtor of
your singleton
//| class T protected.
//| second, make both the chosen instantiation policy (and
singleton_destroyer<T> if
//| lazy_instantiation is chosen) friend(s) of T.
//| third, applying the Coplien::Curiously Recurring Template pattern,
//| define T as in one of the following examples (other combinations
possible, too).
//|
//| one that is most common (multi-threaded):
//| class T : public singleton<T> {...};
//|
//| one that uses static storage (multi-threaded):
//| class T : public singleton<T, static_instantiation> {...};
//|
//| one that uses local static storage (single-threaded, Meyers-like):
//| class T : singleton<T, local_static_instantiation, ZThread::NotLocked>
{...};
template <typename T,
typename I/*instantiation policy*/=lazy_instantiation,
typename L/*lock type*/=boost::mutex>
class singleton : private I, private boost::noncopyable
{
public:
static T* instance();
protected:
singleton() {} //neither direct instantiation/usage of
singleton<T>
virtual ~singleton() = 0; //nor accidental/sneak destruction
};
template <typename T, typename I, typename L>
T*
singleton<T,I,L>::instance()
{
static T* p = 0;
if (!p)
{ //Schmidt::Double-Checked Locking, ensuring thread safety
static L lock; //uses local static storage to avoid static member
construction
boost::mutex::scoped_lock<L> g(lock);
if (!p) I::make(p);
}
return p;
};
template <typename T, typename I, typename L>
singleton<T,I,L>::~singleton()
{
}
} //namespace ste::pattern
} //namespace ste
#endif //STE_PATTERN_SINGLETON_HPP
-- Greg
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk