|
Boost : |
From: Dave Handley (dave_at_[hidden])
Date: 2005-01-08 04:47:15
Jason,
I just want to clarify a couple of points in your last post:
<snip>
>
> Since my revision, the singleton is not forced to be created
> statically. Singleton A will only be created statically if client code
> creates a static dependency on A, or if another singleton B has a static
> lifetime and depends upon A. If the actual method of allocation (new)
> should be made more flexible, would adding a template allocator
> parameter similar to that used by stl containers be sufficient?
>
I've just looked at your code again, and I actually note that the only
creation policy you use is effectively the CreateUsingNew policy of Loki.
The singleton is always created using a new in the AddDependency function.
Providing an allocator template is essentially what is done in Loki so that
would suffice to resolve this particular difference.
>> ...a single lifetime policy (dependencies)
>
> Again, because I removed the enforced static dependency that was in the
> original code, my singleton should allow multiple lifetime types based
> on where and how dependencies are used.
>
Sorry, I think you have misunderstood me. I know that the dependencies
method can be used in different ways, but it is still only a single policy.
The reason for providing completely different policies for the lifetime
policy is just that different projects require different solutions. I know
for example that the dependencies model would fall down very quickly in the
system I code in at present. We have a singleton that is the root of the
tree that contains all the data in the system. Everyone uses this
singleton, but doesn't tend to hold out references (dependencies). Under
your dependency model, we would be almost forced to place a dependency in
the main function - but here lies the problem. We actually have a number of
different products which share the code base, but provide different main
functions (and a few key interface classes) - this would mean we are
coupling the main singleton to loads of places in the code. Using
lifetimes, we can trivially make sure that this is the last singleton to
come down.
>
> Doesn't the same potential problem exist with ref-counted smart
> pointers? Wouldn't it be accurate to say that it should be illegal to
> create singletons with cyclic dependencies in the first place? With my
> current design, just getting a pointer to the singleton introduces a
> dependency. Thus, if a singleton B requires access to a singleton A for
> only certain function calls, it should simply get access to the pointer
> to A's instance at the beginning of those function calls. A singleton
> should only own a dependency to another singleton if it actually
> requires it for its entire lifetime, so cyclic dependencies simply don't
> make sense to write.
There is exactly the same problem with reference counted smart pointers.
That is why the boost smart pointer library includes the weak_ptr. If you
(for example) write a composite tree, and use smart pointers in both
directions, the tree will never be destroyed - so you normally make the
parent pointer a weak pointer. You are absolutely right in saying that it
makes no sense to have a cyclic singleton dependency - but I can guarantee
that in a big enough system, someone would make the mistake and put one in -
especially since you don't explicitly check for cyclic dependencies
(something that is hard to do anyway).
>
> Hard coding a longevity number for each singleton seems dangerous to me,
> because it is difficult to see what order all the singletons would be
> created in without tracking each down and looking at it. Any time a new
> singleton is added, many of the numbers might need to be shuffled.
> Explicitly owning a dependency or getting the instance seems more
> intuitive to me as to document what the singleton actually requires.
>
Generally, if I use longevities, I place the longevity numbers in a header
file. Either explicitly creating a longevity number for every singleton in
there, or creating a set of longevity numbers that every singleton uses
(possibly sharing numbers when there are no dependencies).
I'm not saying dependencies are wrong - I'm just saying that a generic
implementation should really provide the choice. I prefer to use
longevities - you clearly prefer the dependencies - other people prefer to
use Phoenix Singletons (singletons that re-create themselves from their own
ashes if they are re-accessed after destruction). Even though I prefer
longevities, there are some systems where I would probably use a different
lifetime policy because it made sense to do so there. I would personally
recommend having a read of Alexandrescu's book, especially the sections on
the lifetime policies, then browsing the Loki code. If you implemented the
allocation policy, used CRTP, implemented a threading policy, and also
looked at integrating some different lifetime policies, then I personally
think that you would have an ideal library to put forward for inclusion in
Boost.
Dave
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk