27

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
};
Anon
  • 2,608
  • 6
  • 26
  • 38
  • 1
    The second one is inherently thread-safe, and also won't report memory leaks if a memory-leak checker is used. – Some programmer dude Oct 24 '12 at 10:41
  • 1
    @JoachimPileborg - only guaranteed threadsafe in fully conformant C++11, AFAIK. – Roddy Oct 24 '12 at 10:43
  • @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)? – Nawaz Oct 24 '12 at 10:44
  • 1
    @Nawaz: It gets created exactly once, in one of those threads, and is only returned after it has been created. – Mankarse Oct 24 '12 at 10:45
  • @Nawaz : http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11 – Roddy Oct 24 '12 at 10:45
  • 1
    @Anon - which books - Can you give an example? – Roddy Oct 24 '12 at 10:48
  • @ROddy Gang of Four .Page 129, AdDison-Wesley edition – Anon Oct 24 '12 at 10:50
  • 1
    @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. – Mankarse Oct 24 '12 at 10:52
  • 2
    @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. – Mike Seymour Oct 24 '12 at 10:53
  • @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 Oct 24 '12 at 10:54
  • @MikeSeymour Fair point. but there are other articles too. – Anon Oct 24 '12 at 10:57
  • 1
    Singleton use is bad design most of the time it gets used. – CashCow Oct 24 '12 at 11:02
  • 1
    @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. – molbdnilo Oct 24 '12 at 11:25
  • Possible duplicate of [C++ Singleton design pattern](https://stackoverflow.com/questions/1008019/c-singleton-design-pattern) – Trevor Boyd Smith Sep 04 '18 at 12:10

7 Answers7

21

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.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Accepting this answer because it explains the difference and why. But upvotes to everyone. Thanks – Anon Oct 24 '12 at 11:06
  • 2
    +1 for calling Singleton and anti-pattern. I don't necessarily agree with "never use" but certainly "rarely use". – CashCow Oct 24 '12 at 11:26
  • "...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? – 463035818_is_not_an_ai Jul 13 '17 at 15:50
9

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.

Mankarse
  • 39,818
  • 11
  • 97
  • 141
  • 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? – Anon Oct 24 '12 at 10:46
  • But the disadvantage is non-deterministic destruction, so if you have many of these you cannot select the order in which they are destroyed. – CashCow Oct 24 '12 at 10:57
  • @CashCow: Indeed. However, I weep for the program in which that is important. – Mankarse Oct 24 '12 at 10:59
4

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.

Roddy
  • 66,617
  • 42
  • 165
  • 277
  • 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. – Sandeep May 11 '15 at 09:35
  • 2
    @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. – Roddy May 11 '15 at 10:04
4

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.

Ivan Vergiliev
  • 3,771
  • 24
  • 23
3

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.

CashCow
  • 30,981
  • 5
  • 61
  • 92
  • 1
    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). – Mankarse Oct 24 '12 at 10:44
  • C++11 has [`std::call_once`](http://en.cppreference.com/w/cpp/thread/call_once) and [`std::once_flag`](http://en.cppreference.com/w/cpp/thread/once_flag). – Nawaz Oct 24 '12 at 10:46
  • 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 Oct 24 '12 at 10:55
1

One advantage is that you do not have to check whether the singleton has already been instantiated.

Another is that you do not have to worry about de-allocating any memory.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
-3

How about a non-local static? Anyone see a problem with this?

class Singleton
{
    static Singleton singleton;
    Singleton();
    // etc

public:
    static Singleton &Instance() { return singleton; }
};

Singleton Singleton::singleton;

// etc
Kalf
  • 1
  • 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 `static`s 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" – underscore_d Dec 26 '15 at 15:51