Difference between Singleton implemention using pointer and using static object

21,800

Solution 1

why do books/articles prefer implementation#1 over implementation#2?

Because most articles describing the Singleton anti-pattern don't fully understand all the hidden dangers when trying to implement it safely in C++. It's surprisingly difficult to get it right.

What is the actual advantage of using pointer in implementation of Singleton class vs using a static object?

Using a pointer, with new but no delete, ensures that the object will never be destroyed, so there is no danger of accessing it after its lifetime has ended. Combined with the "lazy" creation, the first time that it's accessed, this guarantees that all accesses are to a valid object. The disadvantages are that creation is not thread-safe, and that the object and any resources it acquires are not released at the end of the program.

Using a local static object, creation is thread-safe on any compiler that supports the C++11 threading model; also, the object will be destroyed at the end of the program. However, it is possible to access the object after its destruction (e.g. from the destructor of another static object), which could lead to nasty bugs.

The best option is to avoid static data, and globally-accessible data, as much as possible. In particular, never use the Singleton anti-pattern; it combines global, static data with weird instantiation restrictions that make testing unnecessarily difficult.

Solution 2

The second version (using a local static variable) has significant advantages.

It does not require use of the free-store, and so will not be detected as a memory leak. It is thread-safe (in C++11). It is shorter and simpler.

The only downsides are that it is impossible to make it portably threadsafe (for pre-C++11 compilers), and that it does not give you the option of explicitly destroying the singleton instance.

Solution 3

I'd always prefer the second, but the first does have a couple of potentially interesting advantages:-

  • Clarity - the checking of the pointer being null is effectively what the compiler does under the hood when constructing static objects. From a 'learning' perspective, it's instructive to understand what's happening when you use static objects in method scope.

  • Lazy Allocation - in the first case, the Singleton object is heap-allocated. If your function never runs, the object is never constructed and never consumes memory. But, in the second case, memory is assigned by the linker to hold the object before the program starts, even though 'construction' is lazy.

Solution 4

The second one has non-deterministic destruction. The first one, you are in control as to when you delete the pointer, if at all.

The first construct is not thread-safe, of course, but can be made so with boost::call_once (or std::call_once if available)

The second construct was common enough that many compilers made it thread-safe even if technically by the standard it isn't (although by the standard the object should only be created once, I'm not sure about the standard's view on completion of the construction before another thread uses it).

If there is no issue with the order of destruction then you can go ahead and use the static version, as long as your compiler guarantees it as thread-safe.

Solution 5

The second example is known by the name "Meyers' Singleton", because it was published first in either "Effective C++", or "More Effective C++". I'm not sure which one, but both were published after "Design Patterns" - so the Gang of Four might just as well have been unaware of the second pattern when their book was written.

Also, the first approach is much more standard for other languages - you can do the first one in Java or C#, but not the second, so people coming from different backgrounds could be another reason for the first one to be more famous.

On the technical side, with the first approach you can control when the singleton is destroyed, but this could also bring you a lot of headaches.

Share:
21,800

Related videos on Youtube

Anon
Author by

Anon

Updated on December 14, 2020

Comments

  • Anon
    Anon over 3 years

    EDIT: Sorry my question was not clear, why do books/articles prefer implementation#1 over implementation#2?

    What is the actual advantage of using pointer in implementation of Singleton class vs using a static object? Why do most books prefer this

    class Singleton
    {
      private:
    
        static Singleton *p_inst;
        Singleton();
    
      public:
    
        static Singleton * instance()
        {
          if (!p_inst)
          {
            p_inst = new Singleton();
          }
    
          return p_inst;
        }
    };
    

    over this

    class Singleton
    {
      public:
        static Singleton& Instance()
        {
            static Singleton inst;
            return inst;
        }
    
      protected:
        Singleton(); // Prevent construction
        Singleton(const Singleton&); // Prevent construction by copying
        Singleton& operator=(const Singleton&); // Prevent assignment
        ~Singleton(); // Prevent unwanted destruction
    };
    
    • Some programmer dude
      Some programmer dude over 11 years
      The second one is inherently thread-safe, and also won't report memory leaks if a memory-leak checker is used.
    • Roddy
      Roddy over 11 years
      @JoachimPileborg - only guaranteed threadsafe in fully conformant C++11, AFAIK.
    • Nawaz
      Nawaz over 11 years
      @JoachimPileborg: The second one is inherently thread-safe? How? What if two threads call the function concurrently? When does the static local object get created (and by which thread)?
    • Mankarse
      Mankarse over 11 years
      @Nawaz: It gets created exactly once, in one of those threads, and is only returned after it has been created.
    • Roddy
      Roddy over 11 years
    • Roddy
      Roddy over 11 years
      @Anon - which books - Can you give an example?
    • Anon
      Anon over 11 years
      @ROddy Gang of Four .Page 129, AdDison-Wesley edition
    • Mankarse
      Mankarse over 11 years
      @Anon: The C++ in Gang of Four should not be considered as even remotely indicative of good style. The book is rather old, and it is about patterns, rather than about the details of their implementations.
    • Mike Seymour
      Mike Seymour over 11 years
      @Anon: That book was written almost twenty years ago. Both the language, and our understanding of how to use it effectively, have changed considerably since then.
    • Anon
      Anon over 11 years
      @Mankarse , I thought that was the go-to book for anything related to Design patterns? Which book would you recommend for C++/Design patterns then? Thanks
    • Anon
      Anon over 11 years
      @MikeSeymour Fair point. but there are other articles too.
    • CashCow
      CashCow over 11 years
      Singleton use is bad design most of the time it gets used.
    • molbdnilo
      molbdnilo over 11 years
      @Anon: It's the go-to book as a catalogue - not implementation - of some OO design patterns that were common and useful in the early nineties. Most of them still are. You should view the code (which is just sample code, not a reference implementation) more as an historic artifact illustrating how people wrote C++ in a different era.
    • Trevor Boyd Smith
      Trevor Boyd Smith over 5 years
      Possible duplicate of C++ Singleton design pattern
  • Mankarse
    Mankarse over 11 years
    The initialisation of local statics is thread safe in all versions of the language that have threads. (But the point stands that it is not threadsafe in many pre-C++11 compilers).
  • Anon
    Anon over 11 years
    Yes, that is the question, why do books prefer the first one over the second one? Does the first one have any advantage that the second implementation does not?
  • Nawaz
    Nawaz over 11 years
  • CashCow
    CashCow over 11 years
    static version is thread-safe with most compilers, it wasn't always. C++11 standard is that compilers must make it thread-safe. Previous standard never said anything about threads.
  • CashCow
    CashCow over 11 years
    But the disadvantage is non-deterministic destruction, so if you have many of these you cannot select the order in which they are destroyed.
  • Mankarse
    Mankarse over 11 years
    @CashCow: Indeed. However, I weep for the program in which that is important.
  • Anon
    Anon over 11 years
    Accepting this answer because it explains the difference and why. But upvotes to everyone. Thanks
  • CashCow
    CashCow over 11 years
    +1 for calling Singleton and anti-pattern. I don't necessarily agree with "never use" but certainly "rarely use".
  • Sandeep
    Sandeep about 9 years
    In the second case memory is not allocated for locally declared static objects (assuming Instance() is not called) as opposed to static member variable. It can be verified by adding a print statement in the constructor.
  • Roddy
    Roddy about 9 years
    @sandeep. You're confusing construction with allocation. The object will typically be statically allocated by the linker, so is consuming memory even though it hasn't been constructed yet.
  • underscore_d
    underscore_d over 8 years
    Um, yes...there is a fundamental problem with this. For instance, where would you define the instance? How would you ensure it was instantiated before any other translation unit tried to access it? Trick questions: The problems resulting from using global statics are precisely why a function-local instance is used (in either way illustrated by the OP) as a 'guard'. Just go read about the well-known "static initialisation order fiasco"
  • 463035818_is_not_a_number
    463035818_is_not_a_number almost 7 years
    "...ensures that the object will never be destroyed" I just read the gof singleton chapter and was a bit surprised that they dont mention at all the destruction of the singleton. Is it because it really doesnt matter or did they simply forget to discuss it?