|
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 ->());
proxy->whatever();
> >>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);
or
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 http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk