
From: Jason Hise <chaos@ezequal.com>
From: Jason Hise <chaos@ezequal.com>
Rob Stewart wrote:
There are explicit create and destroy member functions, and the singleton is generally scheduled to be automatically destroyed at one
Rob Stewart wrote: 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@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;