Boost logo

Boost :

From: Dan Rosen (dan.rosen_at_[hidden])
Date: 2005-03-25 20:30:32


> But this is not what I was suggesting. [snip]
> This makes it so that client code can indeed do absolutely nothing, and
> still be guaranteed that rogue instances cannot be created.

Ah, interesting pattern. Thanks for the clarification. I think there
are two separable design concerns here. One is the singleton behavior,
and the other is the non-instantiable behavior. Singleton conceptually
has a dependency on non-instantiable, but there isn't a reverse
dependency there. So I'd separate the two something like this:

  class noninstantiable {
  protected:
    virtual void myob () = 0;
  };

  template <typename T> class instantiable : public T {
  private:
    virtual void myob () { }
  };

That's the first half -- it's saying something like "a class deriving
from noninstantiable is not instantiable except in certain contexts
where you explicitly declare it to be instantiable." [Clients are also
prevented from calling myob().] This doesn't prevent clients from
intentionally saying "I want to instantiate foo here" by using
instantiable<foo> explicitly, but it does prevent unintentional
instantiation, which is probably good enough.

The second half is the singleton part. You'd do something like:

  template <typename T> class singleton : public instantiable<T> {
    // ...
  };

All that said, there's still a flaw in your approach, which I've
inherited in mine. That is: neither of our singleton<> class templates
actually force clients to derive from their intended bases
(singleton_base in your case, and noninstantiable in mine). In other
words, your assertion that "client code can indeed do absolutely
nothing" isn't precisely true: clients still have to derive from a
special base to be safe, and there's no guarantee that will be done.

Addressing your original question regarding whether enabling the
virtual function safety mechanism in debug mode, that seems
reasonable. Assuming there's nothing wrong with the way I've
refactored things here, you can contain that safety mechanism within
the noninstantiable/instantiable hierarchy without polluting the
singleton's interface. (Just wrap the declarations for "myob" in an
#ifdef DEBUG block and you're done.)

But I'd still like to know your motivation for not just doing what
strikes me as the obvious and idiomatic thing: making clients define
private ctor/dtor. It's trivial to do, everybody knows what it means,
and you get the same safety without any virtual function overhead. Is
there some reason you're trying so hard to avoid this?

Cheers,
dr


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