Boost logo

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