Re: Gamma's Singleton pattern
* Joshua Maurice:
On Sep 3, 11:38 pm, "Alf P. Steinbach" <al...@start.no> wrote:
There are two main ways of defining the singleton with all header file code.
They use different ways to tell the linker that multiple definitions of the
variable are OK, that they're the same, and that the linker should just pick one.
The first and most common is known as Meyer's singleton, and simply makes the
variable a local static variable:
struct Log
{
static Log& instance()
{
static Log theInstance;
return theInstance;
}
};
This Meyer's singleton will however be destroyed before static variables that
have been initialized before it, so those static variables can't use the logger.
Which presumably is the reason why your example code uses a pointer.
Using a pointer is however no problem with a Meyer's singleton:
struct Log
{
static Log& instance()
{
static Log* theInstance = new Log;
return *theInstance;
}
};
This dynamically allocated Meyer's singleton, however, has the opposite problem,
namely that the singleton will never be destroyed.
In order for outside code to be able to influence the time of destruction (or
whether that should occur at all) you need a pointer that's not just a local
static variable, a pointer with external linkage.
Errata: Instead of "need" I should have written "can use". An alternative is a
Meyer's singleton using a (additional) Meyer's singleton for access to the
pointer variable. Which however is a bit unnatural, at least to me.
Which presumably is the reason
why your example is not a Meyer's singleton.
The FAQ offers a slightly different take.
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14
It's just presented in opposite order, and not addressing the issue of
all-header code. ;-)
As long as X calls Log::instance in X's constructor, then Log's
constructor will exit first, it will start its lifetime first, then X
will be constructed. LIFO rules for static object lifetimes, so as the
Log object finished construction first, it will be destroyed last.
Yes. In that scenario the X instance hasn't been (fully) initialized before the
singleton, and so the singleton instance isn't destroyed before the X instance.
However, as I wrote, the singleton will be destroyed before static variables
that /have/ been initialized before it, e.g. a Y instance that accesses the
singleton only in the Y destructor, and I guess that's what you refer to below:
The suggested course of action is just to leak the Log object unless
there is a compelling reason to destroy it, as ensuring all static
objects which use Log call Log::instance in their constructors is
tedious and error prone.
A sort of obvious solution is to make the 'instance' member protected, which of
course means a less straightforward usage from free-standing routines, but I
don't think that's a problem.
Also, more general singleton lifetime management is not so very tedious and
error prone when you can reuse others' work ;-).
For example, "Modern C++ Design" has a good deal of support for singleton
lifetime management, and I guess that's part of Loki.
Cheers & hth.,
- Alf