How to Avoid Singletons in Modern C++
Global objects are bad
Global objects are bad, m’kay? You will hear this all the time, from programmers young and old, recited as an article of faith. Let’s look into why this is.
A global object lives in the global namespace. There is only one of these, hence the name “global.” The global namespace is the outermost declarative region of a translation unit. A name with global namespace scope is said to be a global name. Any object with a global name is a global object.
A global object is not necessarily visible to every translation unit of a program; the one-definition rule means that it can only be defined in one translation unit. However, a declaration can be repeated in any number of translation units.
Global objects have no access restrictions. If you can see it, you can interact with it. Global objects have no owner other than the program itself, which means no sin-gle entity is responsible for it. Global objects have static storage duration, so they are initialized at startup (or static initialization) and destroyed at shutdown (or static deinitialization).
This is problematic. Ownership is fundamental to reasoning about objects. Since nothing owns a global object, how can you reason about its state at any time? You might be calling functions on that object and then, suddenly and without warning, another entity may call other functions on that object without your knowledge.
Worse still, since nothing owns global objects, their construction sequence is not determined by the standard. You have no idea in which order global objects will be constructed, which leads to a rather frustrating category of bug that we shall cover later.