/* * Singleton.hpp * * Created on: Mar 10, 2010 * Author: crueger */ #ifndef SINGLETON_HPP_ #define SINGLETON_HPP_ #include #include #include "defs.hpp" /** * This template produces the generic singleton pattern using the CRTP idiom. * *

Singleton Howto

*

Introduction

* * A Singleton is a class of which there can only be a single Object in the programm. It is * described as an design-pattern in Gof:96 (the famous design-pattern book). In the * molecuilder there are so far several Singletons serving a wide range of purposes: * * - the World, which handles all atoms, molecules and bonds * - the ActionRegistry, which stores all created actions by name for later use * - the UIFactory, which is an AbstractFactory (another design-pattern from Gof:96) and * handles all creation of gui elements to ensure a single type throughout the programm * - the logger and errorLogger classes, that can be used to output messages on the screen * depending on certain conditions * * Because those classes can only be instantiated once you cannot simply call new World() * or delete on them. Rather they have to be constructed and accessed using the singleton * mechanism. This mechanism consists of four static functions (and a fifth that is used internally, * but we will get to that later). These functions are: * * - Singleton& Singleton::getInstance() : returns the instance of the singleton as * a reference * - Singleton* Singleton::getPointer() : returns the instance of the singleton as a * pointer * - void Singleton::purgeInstance() : destroys the single Instance of the singleton * - Singleton& Singleton::resetInstance() : resets the Singleton, i.e. destroys the * old instance and creates a new one * * If you need the instance of the singleton it is usually fine just to use one off the accessor * functions (i.e. getInstance() or getPointer(). Any creation of the * Singleton is then handled by these functions, so that the same object will be returned whenever * one of these functions is called. This easy process is true for most singletons you will need * to use. The only special singleton is the UIFactory. * *

Special functions of the UIFactory

* * If you simply call the getInstance() method of the UIFactory class the program * will crash. This happens, because the UIFactory in itself is abstract and needs to know what * kind of user interface it should produce later on. You need to tell the class the type of UI * using the void UIFactory::makeUserInterface(InterfaceTypes type) method. This will * also take care of creating the sole instance, so that the accessor functions will work afterwards. * What this also means is, that you cannot reset() the UIFactory, because at that * point it wont know anymore what to construct. A sequence of UIFactory::purgeInstance(), * UIFactory::makeUserInterface() and UIFactory::getInstance() will work * though. * * In order to make life easier and propagate changes to the singleton mechanism to all those * classes, there is a simple framework class that can be used to make any other class a * singleton through inheritance. This class can be found in the Pattern directory. * *

How to make a class Singleton

* * Most of the time you will only need singletons that don't require additional * information for creation. So I will cover the basic case for constructing singletons * first and then explain what has to be changed to make it accept special parameters. * Singletons are created by inheriting from the Singleton template * using the Curiously recurring template pattern (CRTP). What this means is, that the * class they inherit from carries the inheriting class as a template parameter. For example * class MySingletonExaple : public Singleton{...}. If you * want to know more about this idiom have a look at the * wikipedia * page for this idiom, but don't worry if you don't quite get how this works for now, for * the use of the singleton framework this is not important. * * If you want to make a class a singleton you can use the following sequence of steps. * * - Inherit from the singleton pattern using the CRTP as above:
* @code * class MySingletonExaple : public Singleton{ ...} * @endcode * - Make constructor and destructor private to avoid creation or destruction from * outside the class:
* @code * class MySingletonExaple : public Singleton{ * private: * MySingletonExample(); * ~MySingletonExample(); * ...} * @endcode * - give the inherited class access to the class internals using a friend declaration:
* @code * class MySingletonExaple : public Singleton{ * friend class Singleton; // don't forget the template parameters here * private: * MySingletonExample(); * ~MySingletonExample(); * ...} * @endcode * * - include the file "Patterns/Singleton_impl.hpp" that carries the implementation details of * the singleton functions in your implementation file of the class. * - make the compiler construct the template instantiations. For this you can use the defined * keyword CONSTRUCT_SINGLETON(name) at any toplevel point in the implementation * file:
* @code * void MySingletonExample::foo(){...} * void MySingletonExample::bar(){...} * CONSTRUCT_SINGLETON(MySingletonExample) // no ; after this * @endcode * *

Singleton with initialization parameters

* * Sometimes it is necessary for a singleton to be passed some initilization parameters. For * example the UIFactory mentioned above needs to know what kind of user interface it has to * produce. Making a singleton that takes initialization parameters is only sligtly different * from the steps lined out above. Here are all the differences: * * - pass an extra false to the template to deactivate the standard instantiation * mechanism * - write a method that handles the special parameters and instantiation. In this method you * can use the setInstance(T*) method inherited from the singleton pattern to set * the created instance. The setInstance() method will only work when the * false template parameter has been set and produce errors otherwise. * */ template class Singleton { private: /** * simple auto_ptr that is used by Singleton template * * This ptr_t allows destruction of the object using a private destructor, * when only the Singleton pattern is friend with the class * * All methods have similar sematics to auto_ptr */ class ptr_t { public: ptr_t(); ptr_t(T* _content); ~ptr_t(); T& operator*(); T* get(); void reset(T* _content); void reset(); ptr_t& operator=(const ptr_t& rhs); private: mutable T* content; }; /** * This object handles the actual creation inside the singleton * * Using template specialization this will allways know what it can * do or cannot do at compile time */ template struct creator_t { inline static creator_T* make(); inline static void set(creator_T*&,creator_T*); }; // specialization to allow fast creations /** * Specialized template that allows automatic construction only */ template struct creator_t{ inline static creator_T* make(){ return new creator_T(); } inline static void set(creator_T*&,creator_T*){ assert(0 && "Cannot set the Instance for a singleton of this type"); } }; /** * specialized template that allows setting only */ template struct creator_t{ inline static creator_T* make(){ assert(0 && "Cannot create a singleton of this type directly"); } inline static void set(ptr_t& dest,creator_T* src){ dest.reset(src); } }; // this is used for creation typedef creator_t creator; //< the creator used public: // make the state of this singleton accessible static const bool may_create=_may_create; //!< the type of singleton that we have /** * returns the instance of this Singleton as a reference * * If no Singleton exists at this point and we are allowed to create one * a new one is created and stored inside the singleton * * If no automatic creation is allowed, make sure to create an instance first * using the appropriate methods of the derived class. Otherwise this method * would fail. */ static T& getInstance(); /** * returns the instance of this singleton as a pointer * * If no Singleton exists at this point and we are allowed to create one * a new one is created and stored inside the singleton. * * If no automatic creation is allowed, make sure to create an instance first * using the appropriate methods of the derived class. Otherwise this method * would fail. */ static T* getPointer(); /** * destroys the current instance of this singleton */ static void purgeInstance(); /** * destroys the current instance of the singleton and immidiately constructs * a new one. Similar to using purgeInstance() and getInstance() * but plays more nicely when observers are present. Especially the new instance is created * before the old one is destroyed so observers can switch their targets, when they are notified * of the destruction. * * If no automatic creation is allowed this method wont work. */ static T& resetInstance(); protected: /** * Method used to set the instance, when no automatic creation is allowed. * * Call this after the instantiation method in the derived class has created * it's instance and want's the singleton mechanism to keep it around for later * use. * * This method will always fail when automatic creation is enabled. */ static void setInstance(T*); /** * empty constructor to allow creation of subclases */ Singleton(); private: /** * the copy constructor is private to avoid accidental copying of Singletons, for example * when passing singletons to functions by value instead of by reference. If you * need copying of singletons call the default constructor in the copy constructor * of the derived object. The copyied object wont be known to the singleton mechanism. */ Singleton(const Singleton&); static boost::recursive_mutex instanceLock; //!< a lock for the pointer of the instance static ptr_t theInstance; //!< the actual instance of the singleton }; #endif /* SINGLETON_HPP_ */