It's eager in that it's initialized in static's dynamic
initialization, before main is started.
Indeed. I dislike having a static pointer in the class though.
So put it in anonymous namespace in the implementation file. It
doesn't matter. Except that if you're trying to implement a
generic Singleton; templates can't use anonymous namespace
unless your compiler supports export.
Someone may mistakenly use it as the authoritative version of
the singleton, when in fact it's just there to ensure
initialization before main. I'd move the pointer out of the
class to (unnamed) namespace scope in a cpp file and give it a
better name, a name like yours, such as
dummyToForceInitBeforeMain.
There was a difference when I used that name. In his code (and
in mine), the pointer really was a pointer to the single
existing instance; in my own code, its called ourInstance ("our"
being the prefix I use for static members, or anything shared
between all instances). Before I created the template, it
usually was in anonymous namespace; in the generic
implementation, however, it's a static member variable. But the
purpose of the pointer isn't (only) to ensure initialization
before main; it is the pointer to the single instance, and it is
what the function Singleton::instance() returns.
This technique does depend on a subtle point---the fact that the
pointer is guaranteed to be null before the dynamic
initialization occurs. This is something I've often counted on
in C++, and seems natural to me, but I can understand some
programmers being bothered by the fact that given:
Singleton* Singleton:
urSingleton = Singleton::instance() ;
, there is code which counts of the fact that ourSingleton is
actually first initialized with a null pointer. And if that's
the case, I can easily see spending an extra, boolean variable
(e.g. dummyToForceInitBeforeMain), in addition to the pointer,
in order to make the issue clear, e.g.:
Singleton* Singleton:
urSingleton = NULL ;
bool dummyToForceInitBeforeMain = (Singleton::instance(), true ) ;
It's certainly clearer. (Using the pointer, as I and the
original poster do, is cleverer. One could easily say, too
clever.)
No difference between this and my version, except this is
simpler, so I'll probably start using this myself.
Yes. What I was complaining about in your version was the
unnecessary extra complexity. For the rest, it's pretty much a
standard solution.
It doesn't. I never said his code was wrong. It does however
have lazy thread-safe initialization, whereas my first example
and the OP's example are eager initialization.
Yes, but I was concerned about getting the mutex. Somehow,
you've got to get at least one mutex constructed before
threading starts; otherwise, you're going to encounter race
conditions constructing the mutex. All the above really does is
defer the problem from the singleton to the getSingletonMutex
function.
I did specifically note this restriction of my solution
several
times.
Indeed. Some platforms require runtime initialization of
mutexes,
-1- so you either program to a particular platform where this
isn't a restriction (Not always possible),
It is in my case
. But yes, not everyone can ignore Windows.
-2- you make a conscious design choice that there will be no
threads during dynamic initialization (Not always possible),
You *can* usually impose that there be no threads using your
singletons before main. Usually, not always.
-3- or you have access to the single point of thread creation
(Not always possible).
Again, you *can* usually impose that any thread which uses your
components be started by your threading library. Again,
usually, not always.
In my company we have external users of our libraries, so 3 is
not an option. Users have direct access to whatever threading
library they want.
You're providing a set of components. You can impose
restrictions on code using those components---in fact, you
almost always have to. In our application, for example, we use
lazy initialization for the master mutex. It will fail if a
thread that uses our components is started before main. But
that's a documented restriction for our components; it doesn't
mean that the third party libraries we link against can't start
threads, and at least one, the Sybase library, does. But of
course, Sybase doesn't use our components.
Also, in my company, we try to support basically every server
platform there is, making 1 not an option. Thus a portable
library writer is left with 2 and making a big explicit note
about this in the interface doc. In my limited experience, the
restriction of no threads before main (or at least threads
which only do trivial things before main) is an acceptable
restriction.
As I said above, the restriction is "no threads which use your
components". In our case, the Sybase threads are far from
trivial (I think). But as third party software, they obviously
don't use our components.
Indeed. I'll let the C++ FAQ handle that one. Suffice to say,
don't destroy when the OS will reclaim resources, i.e. don't
destroy if the process dying makes the leak irrelevant.
For memory, that's usually the case. On the other hand, if the
singleton creates a temporary file...
Which I addressed by making the mutex itself
initialized-on-demand eager-initialized.
Yes. That was my point: you need eager initialization
somewhere.