Library/C++/Creating a Singleton using C++0x
From Athile
< Library
This page is a work-in-progress. It is not yet complete.
It may contain inaccurate, incorrect information. Use at your own risk.
It may contain inaccurate, incorrect information. Use at your own risk.
Overview
A Singleton design pattern g is a common, well-known design pattern g. This article briefly explains a generic way to make a class into a Singleton using C++0x g classes std::shared_ptr<> g, std::weak_ptr<> g, and a helper method.
The basic idea is this:
- Create a global weak_ptr<> to store a reference to the Singleton object
- Add an acquire() method to the class that will create this Singleton on the first call
- Use std::shared_ptr<> to automatically ensure the Singleton is destroyed when the last reference is gone
- Ensure the Singleton constructor and destructor are private to enforce correct usage
Implementation
In your singleton class:
- Add a public acquire() method that calls a template function helper (will be shown in a moment). This must return a std::shared_ptr<> for the automatic release to occur properly.
- Add friend declaration to the template function to ensure only it has access to the protected constructor and destructor
- Add protected/private static singleton object as a std::weak_ptr<>
- Add protected/private constructor / destructor declarations
class Engine { public: //! Acquire the Singleton for the Engine static std::shared_ptr<T> acquire() { return detail::acquireSingleton<Engine>(s_wpEngine); } ... protected: template <typename T> friend std::shared_ptr<T> detail::acquireSingleton (std::weak_ptr<T>&); static std::weak_ptr<Engine> s_wpEngine; Engine(); ~Engine(); ... };
That is all that is required for each Singleton class. Now for the shared acquireSingleton template which does most of the work.
Make note of the following:
- A DeleteFunctor object is used so that only acquireSingleton must be made a friend; otherwise shared_ptr itself would have to be a friend
- This method is completely templatized so the creation-on-first-acquisition logic does not require duplication between classes
template <typename Klass>
std::shared_ptr<Klass>
acquireSingleton (std::weak_ptr<Klass>& global_wptr)
{
// DeleteFunctor is used to expose access to the destructor to shared_ptr
// but no one else.
// See: http://beta.boost.org/doc/libs/1_42_0/libs/smart_ptr/sp_techniques.html
struct DeleteFunctor
{
void operator()(Klass* p) { delete p; }
};
std::shared_ptr<Klass> sp( global_wptr.lock() );
if (!sp.get())
{
sp.reset( new Klass, DeleteFunctor() );
global_wptr = sp;
}
return sp;
}