58

A friend of mine today asked me why should he prefer use of singleton over global static object? The way I started it to explain was that the singleton can have state vs. static global object won't...but then I wasn't sure..because this in C++.. (I was coming from C#)

What are the advantages one over the other? (in C++)

Chathuranga Chandrasekara
  • 19,150
  • 28
  • 95
  • 135

8 Answers8

61

Actually, in C++ preferred way is local static object.

Printer & thePrinter() {
    static Printer printer;
    return printer;
}

This is technically a singleton though, this function can even be a static method of a class. So it guaranties to be constructed before used unlike with global static objects, that can be created in any order, making it possible to fail unconsistently when one global object uses another, quite a common scenario.

What makes it better than common way of doing singletons with creating new instance by calling new is that object destructor will be called at the end of a program. It won't happen with dynamically allocated singleton.

Another positive side is there's no way to access singleton before it gets created, even from other static methods or from subclasses. Saves you some debugging time.

vava
  • 22,949
  • 11
  • 60
  • 78
  • 9
    This is the best way of making singletons. Using new is not common in real code, though there are lots of example's on the internet that seem to show it is good idea (don't believe them). – Martin York Sep 23 '09 at 03:48
  • 4
    Actually, there is no "best" way of making singletons. If this singleton references another singleton in its destructor, it won't work properly. – rlbond Sep 23 '09 at 14:05
  • 2
    Note that this is generally not thread-safe (depends on implementation: e.g. g++ will insert locks, but MSVC will not). – Pavel Minaev Sep 23 '09 at 23:21
  • 8
    If your singleton references another singleton, then you should be forbidden from ever writing another line of code. And certainly from writing more singletons. Then you're stuck in a 1970's mindset where all data must be global. – jalf Sep 24 '09 at 07:01
  • @jalf, singletons should be banned forever :) But they do exist and they do reference each other, that's life for you. – vava Sep 24 '09 at 07:34
  • 2
    ... and then you can make it so that `Printer` won't instantiated by anyone else by making the constructor private and making `thePrinter()` a friend function. – Catskul Oct 05 '10 at 22:02
  • @sabbour, the easiest way is to call all the singletons creation methods before multithreading starts. – vava Dec 31 '10 at 22:31
  • 2
    I'm sure you know this, but it's worth pointing out for the benefit of readers: Global static objects are only susceptible to "[possibly being] created in any order" (i.e. UB) in groups spanning multiple translation units. Within a single TU, they are guaranteed to be created in the order of declaration. – underscore_d Apr 07 '16 at 19:48
  • Also relevant because of changes since 2009/2010: C++11 and forward guarantee that the local-static singleton is now threadsafe; this is sometimes called "magic statics." GCC and Clang have supported it for a while; Visual Studio since VS 2015. – EvanED May 31 '16 at 22:21
30

In C++, the order of instantiation of static objects in different compilation units is undefined. Thus it's possible for one global to reference another which is not constructed, blowing up your program. The singleton pattern removes this problem by tying construction to a static member function or free function.

There's a decent summary here.

Paul
  • 4,066
  • 2
  • 25
  • 53
rlbond
  • 59,991
  • 50
  • 166
  • 218
  • and then you introduce complex race conditions and throw away thread safety because two threads may call that function simultaneously. – jalf Sep 24 '09 at 07:00
  • 2
    Funnily enough, std::cout seeems to work fine, despite being a plain old global object... I'm sure if the order of initialization was such a big problem, the standard committee would have noticed by now. It is only a problem if you overuse globals and have them depend on each others. – jalf Sep 24 '09 at 07:04
  • 2
    @jalf: Do your homework. `cout` and `cin` are specifically specified to be constructed before `main()` by the standard. Other global objects do not get this treatment. Moreover, thread-safe singleton implementations exist and are not difficult to write yourself; you only need a double-lock to prevent double-construction. Personally I try to avoid singletons, I think the pattern is overused. But your lack of C++ knowledge is no reason to downvote me. – rlbond Sep 24 '09 at 13:03
  • 1
    Your double-locking pattern does **not** work in this case. The static object is guaranteed to be initialized **before any function in the same translation unit is called**, which includes the one you wanted to initialize the object, which means it happens before your locks are entered, so they're not much use. :) – jalf Sep 24 '09 at 15:30
  • 4
    @rlbond: There is nothing special about cin and cout. They are treated just the same as other global variables. There are just other tricks you can use to make sure they are initialized correctly. – Martin York Sep 24 '09 at 15:52
  • @jalf. (1) It is not hard to add thread safety. (2) gcc does it automatically. (3) The new standard covers it. – Martin York Sep 24 '09 at 15:53
  • 2
    Every compiler vendor can define the initialization order of std objects themself. They are expected to be initialized before any user code is running. – Lothar Aug 28 '16 at 14:00
8

A friend of mine today asked me why should he prefer use of singleton over global static object? The way I started it to explain was that the singleton can have state vs. static global object won't...but then I wasn't sure..because this in C++.. (I was coming from C#)

A static global object can have state in C# as well:

class myclass {
 // can have state
 // ...
 public static myclass m = new myclass(); // globally accessible static instance, which can have state
}

What are the advantages one over the other? (in C++)

A singleton cripples your code, a global static instance does not. There are countless questions on SO about the problems with singletons already. Here's one, and another, or another.

In short, a singleton gives you two things:

  • a globally accessible object, and
  • a guarantee that only one instance can be created.

If we want just the first point, we should create a globally accessible object. And why would we ever want the second? We don't know in advance how our code may be used in the future, so why nail it down and remove what may be useful functionality? We're usually wrong when we predict that "I'll only need one instance". And there's a big difference between "I'll only need one instance" (correct answer is then to create one instance), and "the application can't under any circumstances run correctly if more than one instance is created. It will crash, format the user's harddrive and publish sensitive data on the internet" (the answer here is then: Most likely your app is broken, but if it isn't, then yes, a singleton is what you need)

Community
  • 1
  • 1
jalf
  • 229,000
  • 47
  • 328
  • 537
  • There are some legitimate uses for the singleton pattern. It's overused, but there are some cases where it's ok (A few examples: a global RNG for a game. Configuration options object. Memory pool controller.) – rlbond Sep 24 '09 at 13:05
  • And like I stated above, order of construction of objects in different compilation units is undefined. You didn't believe me and brought up `cout` and `cin`, but these are special cases defined by the standard. – rlbond Sep 24 '09 at 13:07
  • 1
    There's little reason why a game should use a single global RNG. Why not reduce contention and have one per thread? And you may even want a different one per subsystem. Or per player, in a multiplayer scenario. Configuration options? I can see a use for two easily. You have one set of configurations that are active, and a second set that the user is currently modifying, but has not yet applied. You may **easily** have more than one memory pool. Of course, there *are* legitimate uses for the singleton pattern. But they're extremely rare, and the ones you listed are *not* among them. – jalf Sep 24 '09 at 15:19
  • Actually, maybe I've just become less compromising since I wrote this, but I'd like to revise the above comment, and say that there are *no* legitimate uses for the singleton pattern. – jalf Apr 26 '11 at 18:32
  • I do know in advance how my code will be used in the future. I'm locking down any other possible use now. Change in the future would require significant discussion. So, in that case, Singleton ok? – iheanyi Jun 12 '14 at 16:02
  • @iheanyi no? I don't follow the logic at all. You can make a class which is simple to implement, and which can be easily verified to be correct, and which will work with one instance as well as with multiple instances. **Or** you can make a class which is more difficult to implement, much more fragile, and harder to test and verify as being correct, **and** which can be used in fewer scenarios. How is that a good thing? Remember, by making it a singleton you are not preventing it from being used *incorrectly*. You are preventing it from being used in ways that would otherwise be *correct*. – jalf Jun 13 '14 at 13:17
  • @jalf after spending an afternoon reading more on this - I've been convinced that it is of limited use. In the general case, yes - it is harder to test and more fragile. I however think it is trivial to implement. In my particular situation that motivated using a singleton, I would be preventing the object from being used (by me or other library programmers) incorrectly (only the internal workings of the library are supposed to use it). In effect, it's adding a compile time sanity check instead of shifting it to run time (with assertions). – iheanyi Jun 13 '14 at 21:09
  • 1
    @jalf One reason I'm moving away from using it in my project is that after writing an implementation using a singleton, then doing some reading and more thinking, I've realized I can achieve the same functionality while reducing coupling between classes through a synchronization method that I was going to use anyway. This would reduce complexity and improve testability. But this may stick around as an early design tool to help me flesh out implementation details using the compiler as a check (before enough exists to make use of run time assertions). – iheanyi Jun 13 '14 at 21:14
4

Another benefit of the Singleton over the global static object is that because the constructor is private, there is a very clear, compiler enforced directive saying "There can only be one".

In comparison, with the global static object, there will be nothing stopping a developer writing code that creates an additional instance of this object.

The benefit of the extra constraint is that you have a guarantee as to how the object will be used.

Andrew Shepherd
  • 40,674
  • 26
  • 128
  • 192
  • 1
    "compiler enforced directive saying "There can only be one"" Care to come up with a single use case where this is a **good** thing? It is not a benefit to add arbitrary and unnecessary constraints to your code. It is a benefit if your code is *general* and *reusable*, and it won't be that if the first thing you do is to slap constraints on it you don't need. – jalf Sep 24 '09 at 07:03
  • @jalf: Most code should be general and reusable. But in a large application you can have several objects requiring some central reference - the global application framework. An example would be some kind of lock manager. Different parts of the application creating their own lock managers would be inappropriate. – Andrew Shepherd Sep 24 '09 at 07:26
  • No, you can easily have different lock managers for different components. – jalf Sep 24 '09 at 15:20
  • 7
    @jalf: It depends on the context. But looking at the bigger picture: what you seem to be objecting to is the designer of a class putting constraints on how a class can be used. I would argue that that's an essential part of component design - that's why we can define methods and fields private. – Andrew Shepherd Sep 24 '09 at 23:36
3

Reason 1:
Singletons are easy to make so they are lazy build.
While you can do this with globals it take extra work by the developer. So by default globals are always initialized (apart from some special rules with namespaces).

So if your object is large and/or expensive to build you may not want to build it unless you really have to use it.

Reason 2:
Order of initialization (and destruction) problem.

GlobalRes& getGlobalRes()
{
    static GlobalRes instance;  // Lazily initialized.
    return instance;
}


GlobalResTwo& getGlobalResTwo()
{
    static GlobalResTwo instance;  // Lazy again.
    return instance;
}


// Order of destruction problem.
// The destructor of this object uses another global object so
// the order of destruction is important.
class GlobalResTwo
{
    public:
        GlobalResTwo()
        {
            getGlobalRes();
            // At this point globalRes is fully initialized.
            // Because it is fully initialized before this object it will be destroyed
            // after this object is destroyed (Guaranteed)
        }
        ~GlobalResTwo()
        {
            // It is safe to use globalRes because we know it will not be destroyed
            // before this object.
            getGlobalRes().doStuff();
        }
};
Martin York
  • 234,851
  • 74
  • 306
  • 532
3

Using Singleton("construct on first use") idiom, you can avoid static initialization order fiasco

aJ.
  • 32,074
  • 21
  • 79
  • 124
  • 1
    That article is terrible. The solution proposed is as bad as the problem. By using new in the function you will now never call the destructor. – Martin York Sep 23 '09 at 04:24
  • 1
    This is one of the very few situations where memory leaks are ok, since the program is ending anyways (unless you are on a truly terrible OS that somehow doesn't reclaim the memory). If you read, the next FAQ, he explains why. – coppro Sep 23 '09 at 04:31
  • 3
    From a memory management point-of-view it's OK, but what if the destructor is supposed to be doing extra work? – Michael Foukarakis Sep 23 '09 at 05:19
  • 2
    I recently had an issue where I needed a a singleton destructor to do extra work. I found that using a smart pointer (boost::shared_ptr) for the instance worked well. It may run into the problems related in 10.14 though. – Dan Hook Sep 23 '09 at 13:17
  • @Martin York: The article also says that you can use a reference to a static object. – rlbond Sep 23 '09 at 14:06
1

In C++, there's not a huge amount of difference between the two in terms of actual usefulness. A global object can of course maintain its own state (possibly with other global variables, though I don't recommend it). If you're going to use a global or a singleton (and there are many reasons not to), the biggest reason to use a singleton over a global object is that with a singleton, you can have dynamic polymorphism by having several classes inheriting from a singleton base class.

coppro
  • 13,900
  • 3
  • 54
  • 73
-1

OK, there are two reasons to go with a singleton really. One is the static order thing everyone's talking about.

The other is to prevent someone from doing something like this when using your code:

CoolThing blah;
gs_coolGlobalStaticThing = blah;

or, even worse:

gs_coolGlobalStaticThing = {};

The encapsulation aspect will protect your instance from idiots and malicious jerks.

Sean
  • 501
  • 4
  • 11