4

Is it possible to initialize the Instance of a Singleton when it is really needed?

Consider this pattern taken from the famous "Design Patterns":

class Singleton {
public:
   static Singleton* Instance();
protected:
   Singleton();
private:
   static Singleton* _instance;
}

Singleton* Singleton::_instance = 0; // unit.cpp

static Singleton* Singleton::Instance() {
   if (_instance == 0) {
       _instance = new Singleton;
   }
   return _instance;
}

Now, I think there is a problem in the pattern there, if one desires to provide the Singleton in a library to others: if the user calls Singleton::Instance() from another compilation unit (during a static data member initialization, for example) before _instance is initialized, then a following call of Singleton::Instance() might create another instance of the Singleton, with unwanted results, since _instance might have been initialized to 0 first.

I think one solution is to initialize _instance this way:

Singleton* Singleton::_instance = Singleton::Instance();

Anyway, that makes the initialization not "lazy" for those who don't need to call Singleton::Instance() to initialize their static data.

Are there better solutions so that the inizialization can happen when the Singleton instance is needed?

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
pipex
  • 81
  • 1
  • 3
  • See this question: http://stackoverflow.com/questions/6993400/managing-a-singleton-destructor/6993501#6993501 – Nim Aug 16 '11 at 07:35
  • 2
    You're probably better off not using a singleton. – GManNickG Aug 16 '11 at 07:42
  • 2
    In essence, the question is really about static initialization order. The singleton here is just an example of the problem (or in this case - non-problem). – Eran Aug 16 '11 at 07:51
  • Yes, the better solution is to *not use a Singleton*. – Puppy Aug 16 '11 at 12:34

3 Answers3

7

Static initialization happens before dynamic initialization

The singleton solution you have quoted works because

Singleton* Singleton::_instance = 0;

describes a static initialization (namely zero initialization in this case, but a constant initialization would work as well if used), which is guaranteed to happen before any dynamic initialization (and therefore before any code is run). All requirements of static initialization are guaranteed here, as _instance is a global variable of a built-in type (a pointer) and initialized with zero.

The other solution you have provided does not change anything significant, because still only the zero initialization of _instance is guaranteed to happen before code from other modules is called, as the initialization by Singleton::Instance call is a dynamic one and therefore is subject to static initialization order fiasco.

Implementation - data segment

Note: Static initialization is most often implemented by storing the value of the variable, which was computed compile time, in a data segment of the executable.

Terminology, standard quote

While most programmers (including Bjarne Stroustrup) call the initialization style used in the original singleton implemementation "compile time initialization", the standard calls it "static initialization", as opposed to a "dynamic initialization" (which is what is most often called run-time). See C++0x draft 3.6.2 (shortened, emphasis mine):

3.6.2 Initialization of non-local variables [basic.start.init]

... Non-local variables with static storage duration are initialized as a consequence of program initiation. ... as follows.

2 Variables with static storage duration (3.7.1) ... shall be zero-initialized (8.5) before any other initialization takes place.

Constant initialization is performed: ...

  • if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that appears in its initializer is a constant expression.

Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.

Community
  • 1
  • 1
Suma
  • 33,181
  • 16
  • 123
  • 191
  • 1
    1. It's "translation unit", not "compilation unit". 2. `_instance` is not initialized at compile time. It's initialized at runtime, before `main` is called. – Billy ONeal Aug 16 '11 at 07:14
  • 2. I disagee here. _instance is a global variable of a built-in type (a pointer) and initialized with a constant expression (0), therefore it is initialized compile time. – Suma Aug 16 '11 at 07:18
  • @Suma: There's no way for it to be initialized at compile time. At runtime some code must be generated that sets that memory location to zero. Yes, it's a compile time constant, and the compiler can treat it that way, but the actual setting of the location to zero happens at runtime. Put another way, the compiler does not have access to the memory space of the program when it runs; there's no way it can change anything in the program's memory space at all. – Billy ONeal Aug 16 '11 at 07:23
  • @Billy: You mean in theory, or in practice? You can perform a quick test with a particular compiler and see the result. I am using this with Visual Studio frequently. While "compile time" may seem confusing, there is no code setting it to zero. The variable is already stored in the executable (in the data segment) initialized to the value computed compile time. – Suma Aug 16 '11 at 07:26
  • @Suma: Then the program is still initializing at runtime; it's just that the process of initialization happens from the program being mapped into memory. That's runtime. There's no compiler running; indeed there need not even be a compiler installed on the target machine when it happens. – Billy ONeal Aug 16 '11 at 07:28
  • 1
    @Billy: I am sorry, but what you describe is commonly called "compile time" initialization, because the value is computed compile time. See http://stackoverflow.com/search?q=compile+time+initialization or http://publications.gbdirect.co.uk/c_book/chapter6/initialization.html or (straight from the horse's mouth) http://www2.research.att.com/~bs/C++0xFAQ.html#constexpr – Suma Aug 16 '11 at 07:35
  • @Suma: It might be referred to that way, but the initialization is occurring at runtime. The value may be computed at compile time, yes, but there's no compiler running when the value gets set. Therefore it cannot be compile time. On the other hand, the compiled program is running -- that's runtime. The difference between "compile time initialization" and "runtime initialization" in the context you linked to has nothing to do with when it happens, but whether the value must be set to a compiled constant. (e.g. "compile time" initialization means the compiler may use it as a known constant) – Billy ONeal Aug 16 '11 at 07:41
  • +1. I'm wondering if you really need the ` = 0` after `Singleton* Singleton::_instance`, since it's going to be zero initialized by default anyway. – Eran Aug 16 '11 at 07:55
  • No, you do not need the = 0, but it will do no harm (and no difference) - the initialization is still a zero initialization. In practice it is possible some compilers will place the variable in data segment in one case and in a bss segment in other case, but this is something most programmers are not concerned about. – Suma Aug 16 '11 at 08:05
  • +1 for massively expanding your answer and adding standards refs. – Billy ONeal Aug 16 '11 at 08:12
4

Now, I think there is a problem in the pattern there, if one desires to provide the Singleton in a library to others: if the user calls Singleton::Instance() from another compilation unit (during a static data member initialization, for example) before _instance is initialized, then a following call of Singleton::Instance() might create another instance of the Singleton, with unwanted results, since _instance might have been initialized to 0 first.

No problem: static variables are zero-initialized before any dynamic initialization takes place.

On the other hand, the code you then introduce as solution to non-existent problem, namely

Singleton* Singleton::_instance = Singleton::Instance();

is problematic – no guarantee about order of (dynamic) initialization between translation unit.

Cheers & hth.,

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • +1 for pointing out the zero initialization bit I forgot about. – Billy ONeal Aug 16 '11 at 08:12
  • Where is the problem with the order of dynamic initialization? If you have two translation units, no matter which one calls Singleton::Instance(), the result is the same. Calls are also thread-safe. – pipex Aug 16 '11 at 08:16
  • 1
    @pipex: Because the call to `Singleton::Instance` might have not happened before your other translation unit(s) try to access `_instance`. – Billy ONeal Aug 16 '11 at 08:18
  • @Billy. Could you give an example? I must miss something, since I don't see the problem about the order: _instance is private and the only way to obtain a pointer to the instance is to call Singleton::Instance(), which sets _instance during the first call only, whatever is the translation unit calling it. – pipex Aug 16 '11 at 08:28
  • 1
    @pipex: Just because some other code points at the variable `_instance` does not mean that `_instance` has yet been constructed. Code which does that exhibits undefined behavior. E.g. the = Singleton::Instance is a static initialization, just as the =0 was which caused the problem in the first place. – Billy ONeal Aug 16 '11 at 08:33
  • 1
    @Billy: but if `_instance` has already been set by a previous call to `Instance`, then `Instance` will return that same value on the second call. Hence, even if the initialization of `_instance` occurs after some previous initialization that called `Instance`, the value won't be changed by the second call. I think all the questioner was missing is that an `=0` initialization *can't* occur after a call to `Instance` and therefore was never harmful in the first place. Ignoring thread-safety the questioner's proposal works, I think, it's just unnecessary. – Steve Jessop Aug 16 '11 at 10:46
  • @Steve: You are correct and we were all wrong. The modified version works more or less the same way as the original one. The variable is zero initialized anyway and the dynamic initialization is no different from a dynamic initialization other users of the singleton would do. – Suma Aug 16 '11 at 12:29
  • @Steve: Yes, his first example works just fine. But if he does = `Singleton::Instance` on the end he does not know whether that assignment has yet occurred in other translation units. (I was assuming that he was saying put the instantiation call there and then just refer to the global variable; in lieu of calling `Instance` in the other translation unit. If that's not the case, due to zero initialization it will just be slower that way because the call `= Singleton::Instance` won't do anything. – Billy ONeal Aug 16 '11 at 15:37
  • @Steve: the proposal is unnecessary, because all I missed when I made the question is that _instance is initialized with a constant expression before any other dynamic init. But why do you say "ignoring thread-safety"? The example in the proposal is thread safe according to the standard, since the static data is not local. – pipex Aug 16 '11 at 15:37
  • @pipex: The standard does not say anything about thread safety. (C++11 will when it's published later this year) Your example is not thread safe because two callers can call `Singleton::Instance` at the same time, go through the If test, then lose control of the CPU (in which case both will try to instantiate the Singleton) – Billy ONeal Aug 16 '11 at 15:41
  • @Billy I think the standard (not c++0x) does specify that global static initializations must be done by a single thread. Then, if you define `Singleton* Singleton::_instance = Singleton::Instance();` in one translation unit, as in the example, and is executed in the first place, then any other calls to Singleton::Instance(), wherever they are, are thread-safe since Instance() becomes a read-only function – pipex Aug 16 '11 at 15:51
  • For a complete solution (and a good, clear discussion of the issues) see http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=D007C96AAD85D4F19A536D596FF010F2?doi=10.1.1.103.337&rep=rep1&type=pdf where Glenn Downing laid out four common approaches to global object initialization, and recommended a "Class-Static-Pointer-with-Lazy-Initialization" approach complete with ordered destruction. – qneill Dec 04 '17 at 15:03
2

use local statics

Singleton* Singleton::getInstance()
{
    static Singleton obj; return &Singleton;
}
user896161
  • 21
  • 1
  • This is the Meyers singleton; it's much clearer than the manual method with the downsides that 1. you can't decide to destroy and reconstruct the object later, and 2. you can't make assumptions about how it behaves in a multithreaded world. – Billy ONeal Aug 16 '11 at 07:24
  • 2
    @Billy: Keep in mind this is thread-safe in C++0x, not that that's widely implemented or solves the other issues. – GManNickG Aug 16 '11 at 07:41
  • 1
    @GMan: Interesting; didn't know that. Nice to keep in mind :) (Do you know if it's thread safe on recent compilers at all?) – Billy ONeal Aug 16 '11 at 07:45
  • 1
    @Billy: I haven't looked. Since none of the major compilers attempted to support the atomics portion of the new standard, I assume they didn't attempt to make static initialization thread-safe. – GManNickG Aug 16 '11 at 07:47
  • 1
    The problem with this is that it creates an order of destruction problem. Generally (there are clearly exceptions), it is preferable to not destruct the singleton, which can only be achieved by dynamically allocating it. – James Kanze Aug 16 '11 at 08:50
  • 1
    @GMan `g++` has attempted to make local static initialization thread-safe for many years now. (I've not looked at the generated code recently, but there were small bugs in the 32 bit Sparc code when I last looked at it.) – James Kanze Aug 16 '11 at 08:51