
Hi all. I was faced with the requirement for a singleton class where the object has to be constructed dynamically and where I wanted to assure that the object is destructed automatically when no longer needed. A solution using shared_ptr and weak_ptr immediately came to mind and after a short google I found http://lists.boost.org/boost-users/2002/10/2014.php. However, if you have to assure that construction and destruction never overlap if you have multiple (sequential) initializations/destructions it gets a bit more complicated :) Well. Here follows what I have come up with and it seems to work pretty well. Any comments welcome. br, Martin Singleton using boost weak_ptr and shared_ptr --------------------------------------------- Requirement: Singleton that is constructed on first use (not on process start) and destroyed after the last "client-code" has finished with it. Note: It is therefore possible that more that one Singleton instances exist within a process's lifetime, BUT there must only be at most one Object active at any given time (Construction must not run before destruction has finished. Starting point: http://lists.boost.org/boost-users/2002/10/2014.php Problem of the simple solution: No protection against multiple initialization and against simultaneous deletion and construction. Solution: The construction and destruction of the singleton instance(s) has to be protected additionally. [CODE:dynamic_singleton.h] #pragma once ////////////////////////////////////////////////////////////////////// #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> #include <boost/scoped_ptr.hpp> ////////////////////////////////////////////////////////////////////// class dynamic_singleton : private boost::noncopyable { public: typedef boost::shared_ptr<dynamic_singleton> shared_t; static shared_t get_instance(); // Interface: void example(int cookie); // ... private: dynamic_singleton(); virtual ~dynamic_singleton(); struct impl; typedef boost::scoped_ptr<impl> impl_t; impl_t pimpl; struct deleter; friend struct deleter; }; [/CODE] [CODE:dynamic_singleton.cpp] #include "dynamic_singleton.h" #include <boost/weak_ptr.hpp> #include <boost/thread/recursive_mutex.hpp> #include <boost/thread.hpp> ////////////////////////////////////////////////////////////////////// #define MESG(msg) \ printf("%s\n", msg); \ /**/ ////////////////////////////////////////////////////////////////////// class atomic_bool : protected boost::noncopyable { public: atomic_bool() : b_(false) {} explicit atomic_bool(bool b) : b_(b) {} inline operator bool() const { boost::recursive_mutex::scoped_lock lock(sync_); return b_; } inline bool operator=(bool b) { boost::recursive_mutex::scoped_lock lock(sync_); b_ = b; return b_; } private: bool b_; mutable boost::recursive_mutex sync_; }; ////////////////////////////////////////////////////////////////////// struct dynamic_singleton::impl : private boost::noncopyable { impl() {} ~impl() {} static void start_construction() { boost::xtime spin_time; spin_time.sec = 1; while(the_object_exists) { boost::thread::sleep(spin_time); } } static void finish_construction() { assert(!the_object_exists); the_object_exists = true; } static void finish_destruction() { assert(the_object_exists); the_object_exists = false; } typedef boost::weak_ptr<dynamic_singleton> internal_shared_t; static internal_shared_t the_object; static boost::recursive_mutex sync_init; static atomic_bool the_object_exists; }; ////////////////////////////////////////////////////////////////////// dynamic_singleton::impl::internal_shared_t dynamic_singleton::impl::the_object; boost::recursive_mutex dynamic_singleton::impl::sync_init; atomic_bool dynamic_singleton::impl::the_object_exists; ////////////////////////////////////////////////////////////////////// struct dynamic_singleton::deleter { void operator() (dynamic_singleton* p) { assert(p); delete p; impl::finish_destruction(); } }; ////////////////////////////////////////////////////////////////////// dynamic_singleton::shared_t dynamic_singleton::get_instance() { // Syncronise Initialization: boost::recursive_mutex::scoped_lock lock(impl::sync_init); MESG(__FUNCTION__); // Acquire singleton pointer: shared_t object_ptr = impl::the_object.lock(); if(!object_ptr.use_count()) { impl::start_construction(); object_ptr.reset(new dynamic_singleton(), dynamic_singleton::deleter()); impl::the_object = object_ptr; impl::finish_construction(); } return object_ptr; } ////////////////////////////////////////////////////////////////////// dynamic_singleton::dynamic_singleton() { pimpl.reset(new impl()); MESG(__FUNCTION__); // For example open a unique system or process global resource printf(" >> Singleton opens the global resouce.\n"); } ////////////////////////////////////////////////////////////////////// dynamic_singleton::~dynamic_singleton() { MESG(__FUNCTION__); // For example close a unique system or process global resource printf(" << Singleton closes the global resouce.\n"); } ////////////////////////////////////////////////////////////////////// void dynamic_singleton::example(int cookie) { printf("%s(%d)\n", __FUNCTION__, cookie); } [/CODE] [CODE:main.cpp] #include "dynamic_singleton.h" #include <iostream> #include <boost/thread.hpp> struct singleton_user { explicit singleton_user(int num) : num_(num) { } void operator()() { using namespace std; printf("%d uses singleton ...\n", num_); dynamic_singleton::shared_t s = dynamic_singleton::get_instance(); s->example(num_); } int num_; }; int main(int argc, char* argv[]) { boost::thread t1( singleton_user(1) ); boost::thread t2( singleton_user(2) ); boost::thread t3( singleton_user(3) ); boost::thread t4( singleton_user(4) ); boost::thread t5( singleton_user(5) ); t1.join(); t2.join(); t3.join(); t4.join(); t5.join(); return 0; } [/CODE]