|
Boost : |
From: scleary_at_[hidden]
Date: 2001-11-15 13:20:47
> From: Mattias Flodin [mailto:flodin_at_[hidden]]
>
> IMHO policies are needed primarily because reality is not so theoretical
> as one would like it to be.
Considering 'real' situations, then:
> You may run into problems with lifetime when
> you try to have several singletons that depend on each other.
Two singletons, A and B, where A depends on B and B depends on A is an
impossible situation. The dependency graph for singletons is a DAG, and
follows the same lifetime rules as objects of static duration. Therefore,
one solution fits every 'real' problem.
> There are
> efficiency concerns, such as avoiding mutex locks on every access if your
> code does not need to be thread safe.
Providing locking for "every access" wouldn't actually gain anything -- the
lock would be released when the pointer is returned. Therefore, one
solution (only lock on the *first* access, using the double-checked locking
idiom) fits every 'real' problem -- you only have the overhead of one lock
per singleton in your program.
> And there's the issue of
> initialization parameters to consider. I'd say a singleton is a singleton
> even if it needs parameters (such as log file name) for initialization.
Yes, now here's something that I've thought of several times, not sure if I
needed to include it or not. I've decided not, following the thoughts:
A singleton with parameters must get its parameter values from somewhere.
This "somewhere" may be hard-coded or dynamic -- where "dynamic" may be
anything from a calculated value to a configuration file.
If "somewhere" is hard-coded, instead of hard-coding it multiple times at
the call to instance(), create a derived class that hard-codes the base
class constructor parameters.
If "somewhere" is dynamic, then that dynamic code can either be in a derived
class, as above, or in another singleton.
Therefore, one solution (default-construct only) fits every 'real' problem.
I read not too long ago in an article (I can't remember where!) about code
re-use being so overly hyped that object-oriented programmers would add
function after function to their code hierarchies until they had a re-usable
class -- that no-one wanted to use! :)
In generic programming, the same phenomenon occurs when well-meaning
programmers add requirements (often optional) to their concepts.
And in generative programming, similar behaviour is found when well-meaning
programmers add policies.
In each case, the interface (be it an abstract base class, a concept, or a
type generator) becomes complicated quickly; but ease of maintenance and
ease of use (*especially* for new users) decreases quickly, with only a
small amount of added flexibility or capability.
The article concluded by stating that some programmers *do* produce
re-usable code. But they do so by *preventing* complication of their
interfaces. Essentially, they do what's necessary, and nothing more.
Look at the smart pointer classes -- in my code, I have a header that simply
imports the boost smart pointers and STL smart pointer, and adds two of my
own:
scoped_ptr
scoped_array
auto_ptr
auto_array [1]
shared_ptr
shared_array
mt_shared_ptr [1]
There has been some talk on this list about using policy classes, and having
a single smart pointer generator. We could allow different deallocation
mechanisms, different sharing capabilities, hooks for user callbacks... But
how many users would ever use them? We'd be adding a lot of complexity with
a small payback.
Just my 2 cents. Wait -- I'm probably up to a good dollar by now! :)
-Steve
[1] The only time I've ever used auto_array was in Win32 overlapped APC
operations
mt_shared_ptr, OTOH, I think would be more generally useful -- it's a
mt-safe version of shared_ptr (but only the count is protected). I use it
for thread mailboxes.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk