
On 5/8/07, Medland, Thomas M <thomas.medland@lehman.com> 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