Singleton Design Pattern 7/1/2016 CS 631: Singleton Design Pattern 1 Outline • Singleton’s Description • Design – Class diagram • Application – Market class • Implementation – Basic – Destroying singleton 7/1/2016 CS 631: Singleton Design Pattern 2 Description • Intent – To ensure that a class has only one instance and provide a global point of access to it. • Applicability – Use when there must be exactly one instance of a class, and it must be accessible to clients from a well-known access point. • Benefits – Controlled access to sole instance – Reduced name space (avoids polluting the name space with global variables) – Permits a variable number of instances. 7/1/2016 CS 631: Singleton Design Pattern 3 Class Diagram 7/1/2016 CS 631: Singleton Design Pattern 4 Market Class • Market class describes the state of the market at any time point. • In its simplest form it can provide an interest rate for any given time interval (maturity). • Consider an application that evaluates various financial instruments in real time. – All evaluations are performed based on market conditions. – Market data should be consistent for all evaluations. • A single market object is required by all modules. Hence it should be implemented as a Singleton. 7/1/2016 CS 631: Singleton Design Pattern 5 Implementation • The description is simple, but implementation issues are complicated. • A singleton is an improved global variable in that one cannot create a secondary object of singleton type. • From a client standpoint the Singleton object owns itself, which means that it is responsible for creating and destroying itself. • Managing a singleton's lifetime causes the most implementation difficulties. 7/1/2016 CS 631: Singleton Design Pattern 6 Static Implementation class Market { public: static double getRate(double maturity) { return rates[maturity]; } private: static map<double,double> refreshRates() {...} static map<double,double> rates; }; map<double,double> Market::rates = refreshRates(); 7/1/2016 CS 631: Singleton Design Pattern 7 Static Implementation: Usage int main() { cout << Market::getRate(1.0) << " " Market::getRate(0.5) << endl; return 0; } 7/1/2016 CS 631: Singleton Design Pattern 8 Static Implementation: Disadvantages • Static functions cannot be virtual! – Cannot change behavior by inheriting from the class. • No central point of initialization or cleanup. – Makes it difficult to create market based on different sources of data. – Makes it difficult to release any resources before the end of the program. 7/1/2016 CS 631: Singleton Design Pattern 9 Basic Implementation class BasicMarket { public: // unique point of access static BasicMarket& getInstance() { if (! instance) { instance = new BasicMarket(); instance->refreshRates(); } return *instance; } double getRate(double maturity) { return rates[maturity); } 7/1/2016 CS 631: Singleton Design Pattern 10 Basic Implementation (cont.) private: BasicMarket() {} BasicMarket(const BasicMarket&) {} BasicMarket& operator=(const BasicMarket&); ~BasicMarket(); // refresh rates data void refreshRates(); static BasicMarket* instance; map<double, double> rates; }; BasicMarket* BasicMarket::instance = 0; 7/1/2016 CS 631: Singleton Design Pattern 11 Basic Implementation: Discussion • Advantages – User code cannot create singletons. – If it's never used, no object is created at the cost of the null test (usually negligible). – Returning a reference from getInstance() prevents clients from trying to delete an object. – Disabling the assignment operator prevents from assigning objects. – Making the destructor private prevents the clients that hold the pointer to BasicMarket from accidentally deleting it. • Disadvantage – Destruction of the object is not controlled. 7/1/2016 CS 631: Singleton Design Pattern 12 Destroying the Singleton • When singleton acquires any resources, such as network connections, etc.; not destroying it properly will lead to a resource leak. • The Singleton should be deleted during the application's shutdown after the use by any modules. • Meyers singleton uses a local static variable. – initialized when the control flow is first passing its definition. – the compiler generates code so that after initialization, the variable is registered for destruction. 7/1/2016 CS 631: Singleton Design Pattern 13 Meyers Singleton class LocalMarket { public: static LocalMarket& getInstance() { static LocalMarket instance; return instance; } double getRate(double maturity) {...} private: LocalMarket() {refreshRates();} LocalMarket(const LocalMarket&) {} LocalMarket& operator= (const LocalMarket &); ~LocalMarket(); void refreshRates(); map<double, double> rates; }; 7/1/2016 CS 631: Singleton Design Pattern 14 Meyers Singleton: Compiler Code static LocalMarket& LocalMarket::getInstance() { // compiler-generated functions and variables extern void __ConstructSingleton(void* memory); extern void __DestroySingleton(); static bool __initialized = false; static char __buffer[sizeof(LocalMarket)]; if (!__initialized) { __ConstructSingleton(__buffer); // register destruction atexit(__DestroySingleton); __initialized = true; } return *reinterpret_cast<LocalMarket*>(__buffer); } 7/1/2016 CS 631: Singleton Design Pattern 15