Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2005-04-28 16:06:47

From: Jason Hise <chaos_at_[hidden]>
> Rob Stewart wrote:
> >From: Jason Hise <chaos_at_[hidden]>
> >>Rob Stewart wrote:
> >>
> There are explicit create and destroy member functions, and the
> singleton is generally scheduled to be automatically destroyed at one
> point or another. As a result, the automatic creation when operator ->
> is invoked is generally a last line of defense, which will recreate the
> instance if it has been destroyed (or in some rare circumstances will
> create the instance for the first time).
> So long as client code makes sure that the instance has already been
> created, that nothing destroys the instance while the raw pointer is in
> use, and that operations which need to be locked are locked manually,
> then that raw pointer is safe to use.

Do the same problems exist when using the singleton object within
the context of operator ->()?

> >>>Having said that, is it really the case that operator *()
> >>>couldn't do the same work as operator ->() (possibly adding an
> >>>exception if you can't get the underlying object)?
> >>>
> >>The difference is that the pointer returned by operator -> is guaranteed
> >>to be used immediately, and by using an intermediate pointer class I can
> >>construct a lock for the duration of the member call (this technique is
> >>described in Modern C++ Design, in the smart pointer section).

Note that I can write this:

   class A { ... };
   // whatever the proxy's name is:
   typedef boost::singleton<A>::some_proxy proxy_type;
   proxy_type proxy(s.operator ->());

> >>Operator * is incapable of constructing this type of temporary lock, and
> >>additionally there is no guarantee that the reference returned would
> >>used and discarded immediately. Once the actual reference is returned,
> >>no more checking can take place.
> >
> >Why can't you return such a proxy from a member function like
> >"get" or "get_object" and let that proxy convert to the singleton
> >type?

That means I can write

   A & object(*proxy);


   A & object(proxy.get_object());

and then I can do what I like with object.

> >That means you can spell "get_unsafe_ptr" without "unsafe"
> >because the proxy ensures that it is safe (as safe as with
> >operator ->(), anyway).
> >
> The action of getting the pointer itself is not unsafe. What is unsafe
> is maintaining that pointer and storing it for an extended period of
> time, during which the singleton could be destroyed and recreated.

Right. As I see it, you've taken steps to ensure that the
singleton survives so long as the proxy returned from
operator ->() lives. Similarly, operator *() can return the same
(or a similar) proxy thus keeping the object alive during its
use. If that proxy provides a conversion operator (gasp!) to the
object managed by the singleton smart pointer, then you get
complete safety and access to the raw object.

The conversion operator (probably only appropriate on a second
proxy type) make this possible:

   A & object(proxy);

> In almost every circumstance, it is preferable for client code to use
> and pass around singleton::pointers rather than singleton *s, just like
> it is preferable for client code to use smart pointers to manage memory
> rather than trying to manage memory and raw pointers manually. Managing
> them manually can be done safely, but it is harder and error prone.

I understand the motivation for the original question. I'm just
having a hard time getting you to see my point, it would seem.
Hopefully, spelling out more of the details has helped.

Rob Stewart                           stewart_at_[hidden]
Software Engineer           
Susquehanna International Group, LLP  using std::disclaimer;

Boost list run by bdawes at, gregod at, cpdaniel at, john at