Boost logo

Boost :

From: Jason Hise (chaos_at_[hidden])
Date: 2005-02-18 23:45:25


Just thought I would release a progress report on the singleton.

I have added a new lifetime policy called static_lifetime, which derives
from the longevity lifetime and just hides the longevity part from
client code, setting it to zero. The result: singletons using the
static_lifetime policy are guaranteed to be destroyed in reverse order
of creation, if they are created. I am thinking that this should be the
default lifetime for the singleton, however I am open to suggestions.
Here is a brief summary of each lifetime in the library. If there are
any ideas for other lifetimes I would love to hear them.

dependency_lifetime - Uses pointers to the singleton as reference
counted dependencies. The singleton, if created, is destroyed upon the
destruction of the last pointer. A static or global pointer must exist
to ensure that the singleton doesn't get destroyed and recreated as the
program executes. Singletons can own dependencies to other singletons
to ensure proper order of creation and destruction. If a circular
reference exists, the singletons owning pointers to each other will
never be destroyed. This was my former choice for the default policy.

longevity_lifetime - Upon first creation of a singleton using this
policy, the singleton instance is registered with a hidden singleton,
the longevity_registry. The longevity_registry has a static pointer to
itself in its constructor, ensuring it lives at least until main exits.
Upon destruction, it destroys the registered singletons in order.
Singletons with lower longevities are destroyed first, and singletons
with the same longevity are destroyed in reverse order of creation.

static_lifetime - Deriving from the longevity_lifetime, this just hides
the longevity template parameter and uses zero. As a result, singletons
using this policy are destroyed in reverse order of creation, and are
destroyed before any longevity based singletons using a longevity
greater than one. As the longevity is an unsigned int, this means most
of them. This is my current choice for a default.

leaky_lifetime - This never destroys the singleton instance. Because of
the extensive framework that it provides in terms of member functions
and classes, all of the other lifetimes derive from it. This way the
other lifetimes can add the specialized destruction behavior without
duplicating all the little details, like creation behavior and member
functions of the pointer class. The leaky lifetime is used internally
by a hidden singleton used in the multiton implementation. This
singleton stores multiton instance holders in a map (ideally this should
be an assoc_vector if one is ever added to boost). It can never be
destroyed because the singletons it stores instance holders to could
potentially be destroyed later, or even be recreated by other singletons
in the process of being destroyed. Fortunately the map only needs to be
destroyed if it needs to free the memory, and this memory which will be
automatically cleaned up by the OS anyway.

I would like to point out that the method of creation is the same
regardless of the lifetime used. An enumerated trait of each lifetime
controls when automatic creation can occur. This can be set to create
the singleton upon creation of a pointer, upon dereferencing a pointer,
both, or neither. If this is set to not automatically create the
singleton at all, client code can explicitly call a create member
function from any singleton pointer. The leaky_lifetime implements all
of these details so that the other lifetimes which derive from it do not
have to worry about it.

Phoenix re-creation ability works automatically for all of these. To
achieve a non-phoenix lifetime, a one_time_creator can be specified
which uses a real creator the first time, and a creator designed to fail
the second time. Numerous failure creators are provided:

null_creator - create simply returns null
throw_creator - create throws an exception (which can optionally be
specified)
assert_creator - causes a boost assertion to fail, and then uses some
other failure creator (defaults to throw_creator) if execution gets past
the assertion

The real creators provided include:
create_using_new - client code can customize with a boolean trait
whether to make it use no throw new
create_using_malloc - client code can make this throw or no throw as well
create_statically - uses a static aligned_storage buffer to hold the
instance, cannot be used with a multiton
create_using_std_allocator - allocates memory with a standard allocator
(which can be customized)

The one_time_creator can be chained to use a different creator for the
first, second, and third creations, ad infinitum. It makes sure to
destroy each instance with the internal creator used to create it.

I am diligently working on the html documentation, which is going to be
quite extensive. It seems like the more documentation I write, the more
ideas I get for improving the library. When I get the documentation
into a coherent state I will upload it. However, I have made so many
changes now that I think an outside perspective would be a good thing
before I start setting class and function names in stone. Thus, an up
to date stable version has been uploaded to the sandbox.

What would be really helpful is if someone could try to write a test
program in a multi threaded context. My background in threading is very
shaky, and I want to be sure that I am using the locking policy the
right way. Is anyone willing to give this a try?

-Jason


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk