Boost logo

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