Presentation is loading. Please wait.

Presentation is loading. Please wait.

Singleton Duchenchuk Volodymyr Oksana Protsyk. 2 /48.

Similar presentations


Presentation on theme: "Singleton Duchenchuk Volodymyr Oksana Protsyk. 2 /48."— Presentation transcript:

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


Download ppt "Singleton Duchenchuk Volodymyr Oksana Protsyk. 2 /48."

Similar presentations


Ads by Google