Download presentation
Presentation is loading. Please wait.
Published byGwendoline Quinn Modified over 9 years ago
1
Singleton Duchenchuk Volodymyr Oksana Protsyk
2
2 /48
3
3 /48
4
What use is that? 4 /48
5
There are many objects we only need one of: -Caches -Dialog boxes -Objects that handle preferences and registry settings -Objects used for logging 5 /48
6
Can’t I just do this by convention or by global variables? 6 /48
7
Singleton is a convention for ensuring one and only one object is instantiated for a given class. Singleton Pattern gives global point of access, just like a global variable, but without the downsides. 7 /48
8
What downsides? 8 /48
9
An example: Global variable -> object is created when application begins. “The road to programming hell is paved with global variables” Steve McConnell 9 /48
10
public class Singleton { } 10 /48
11
public class Singleton { private Singleton() { } } 11 /48
12
public class Singleton { private Singleton() { } public static Singleton getInstance() { return new Singleton(); } 12 /48
13
public class Singleton { private static Singleton uniqueInstance; private Singleton() { } public static Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } 13 /48
14
public class Singleton { private static Singleton uniqueInstance; private Singleton() { } // other useful instance variables here public static Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } //other useful methods here } 14 /48
15
The Chocolate Factory All modern chocolate factories have computer controlled chocolate boilers. The job of the boiler is to take in chocolate and milk, bring them to a boil, and then pass them on to the next phase of making chocolate bars. 15 /48
16
public class ChocolateBoiler { private boolean empty; private boolean boiled; public boolean isEmpty() { return empty; } public boolean isBoiled() { return boiled; } //… } 16 /48
17
public ChocolateBoiler() { empty = true; boiled = false; } public void fill() { if (isEmpty()) { empty = false; boiled = false; //fill the boiler with a milk/chocolate mixture } 17 /48
18
public void boil() { if (!isEmpty() && !isBoiled()) { boiled = true; //bring the contents to a boil } public void drain() { if (!isEmpty() && isBoiled()) { empty = true; //drain the boiled milk and chocolate } 18 /48
19
How might things go wrong if more than one instance of ChocolateBoiler is created in an application? 19 /48
20
The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it. 20 /48
21
21 /48
22
Dealing with multithreading public class Singleton { private static Singleton uniqueInstance; private Singleton() { } // other useful instance variables here public static synchronized Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } //other useful methods here } 22 /48
23
23 /48
24
Options to improve the code 1. Do nothing if the performance of getInstance() isn’t critical for your application 24 /48
25
Options to improve the code 2. Move to an eagerly created instance rather than a lazily created one public class Singleton { private static Singleton uniqueInstance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return uniqueInstance; } 25 /48
26
Options to improve the code 3. Use “double-checked locking” to reduce the use of synchronization in getInstance() public class Singleton { private volatile static Singleton uniqueInstance; private Singleton() { } public static Singleton getInstance() { if (uniqueInstance == null) { synchronized (Singleton.class) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } 26 /48
27
Implementing Singleton (C++) class MyClass { public: static void doSomething(); private: static int _data; }; 27 /48
28
class Singleton { public: static Singleton* Instance() { if (!pInstance_) pInstance_ = new Singleton; return pInstance_; } private: Singleton(); Singleton(const Singleton&); static Singleton* pInstance_; }; // Implementation file Singleton.cpp Singleton* Singleton::pInstance_ = 0; 28 /48
29
//improved class Singleton { public: static Singleton& Instance();... private: Singleton(); Singleton(const Singleton&); Singleton& operator=(const Singleton&); ~Singleton();... }; 29 /48
30
Destroying the Singleton With the class definition we have destructor is never called. 30 /48
31
Meyers singleton Singleton& Singleton::Instance() { static Singleton obj; return obj; } 31 /48
32
A pseudo-C++ representation of the generated code by compiler Singleton& Singleton::Instance() { // Functions generated by the compiler extern void __ConstructSingleton(void* memory); extern void __DestroySingleton(); // Variables generated by the compiler static bool __initialized = false; // Buffer that holds the singleton static char __buffer[sizeof(Singleton)]; if (!__initialized) { // First call, construct object // Will invoke Singleton::Singleton // In the __buffer memory __ConstructSingleton(__buffer); // register destruction atexit(__DestroySingleton); __initialized = true; } return *reinterpret_cast (__buffer); } 32 /48
33
The Dead Reference Problem 33 /48 Three singletons: Keyboard, Display and Log.
34
34 /48 Keyboard Display Log
35
35 /48 Should I use Meyers Singleton?
36
Keyboard is constructed successfully 36 /48 Example Display fails to initialize Display's constructor creates Log
37
Local static objects are destroyed in the reverse order of their creation. Therefore, Log is destroyed before Keyboard. Log::Instance now returns a reference to the "shell" of a destroyed Log object. 37 /48
38
Improvement Let’s add static boolean member variable destroyed_ One function, one responsibility: Create, which effectively creates the Singleton OnDeadReference, which performs error handling Instance, which gives access to the unique Singleton object. 38 /48
39
static Singleton& Instance() { if (!pInstance_) { // Check for dead reference if (destroyed_) { OnDeadReference(); } else { // First call—initialize Create(); } return pInstance_; } 39 /48
40
// Create a new Singleton and store a // pointer to it in pInstance_ static void Create(); { static Singleton theInstance; pInstance_ = &theInstance; } 40 /48 // Gets called if dead reference detected static void OnDeadReference() { throw std::runtime_error("Dead Reference Detected"); } virtual ~Singleton() { pInstance_ = 0; destroyed_ = true; }
41
41 /48 But that doesn’t really fix the problem!
42
The Phoenix Singleton void Singleton::OnDeadReference() { // Obtain the shell of the destroyed singleton Create(); // Now pInstance_ points to the "ashes" of the singleton // - the raw memory that the singleton was seated in. // Create a new singleton at that address new(pInstance_) Singleton; // Queue this new object's destruction atexit(KillPhoenixSingleton); // Reset destroyed_ because we're back in business destroyed_ = false; } void Singleton::KillPhoenixSingleton() { pInstance_->~Singleton(); } 42 /48
43
Singletons with Longevity // Takes a reference to an object allocated with new and // the longevity of that object template void SetLongevity(T* pDynObject, unsigned int longevity); Each call to SetLongevity issues a call to atexit. Destruction of objects with lesser longevity takes place before destruction of objects with greater longevity. Destruction of objects with the same longevity follows the C++ rule: last built, first destroyed. 43 /48
44
Multithreading Singleton& Singleton::Instance() { if (!pInstance_) { Lock guard(mutex_); if (!pInstance_) { pInstance_ = new Singleton; } return *pInstance_; } 44 /48
45
In C++ 11 Meyers Singleton is thread-safety Singleton& Singleton::Instance() { static Singleton obj; return obj; } 45 /48
46
Summary It's relatively easy to protect Singleton against multiple instantiations. The most complicated problem is managing a singleton's lifetime, especially its destruction (C++). There are threading issues surrounding the Singleton design pattern. There is no “best” solution. 46 /48
47
References Head First Design Patterns by Eric Freeman, Elisabeth Robson, Bert Bates, Kathy Sierra Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides Modern C++ Design: Generic Programming and Design Patterns Applied by Andrei Alexandrescu 47 /48
48
Thanks for attention! 48 /48
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.