[smart_ptr] weak_ptr pointer semantics

Hi, Why weak_ptr does not have (smart) pointer semantics? No * or -> or even get(). I often need a pointer type that is a listener to shared_ptr<> (does not affect refcount) but is still usable as a regular pointer type. If providing * and -> operators is for some reason undesirable then just a get() member would be nice as it would allow to implement own wrapper with pointer semantics. get() would return raw pointer from shared counter (so is fast) and not shared_ptr<> as lock() does. -- Szymon Gatner The Lordz Games Studio www.thelordzgamesstudio.com

Because it is not safe to have a pointer to something and not reference count it. See the explanation at http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/weak_ptr.htm for a more detailed argument of the same. If you don't want safety in your pointers, then use raw pointers. If you want safety, then you have to accept the consequences... -Tim On 11/10/2011 7:20 PM, Szymon Gatner wrote:
Hi,
Why weak_ptr does not have (smart) pointer semantics? No * or -> or even get().
I often need a pointer type that is a listener to shared_ptr<> (does not affect refcount) but is still usable as a regular pointer type. If providing * and -> operators is for some reason undesirable then just a get() member would be nice as it would allow to implement own wrapper with pointer semantics. get() would return raw pointer from shared counter (so is fast) and not shared_ptr<> as lock() does.

Because it is not safe to have a pointer to something and not reference count it.
Not sure what you mean here, I still have weak_ptr<> which has a counter and there is a shared_ptr<> (or not) somewhere out there. So counter exists as long as I still have any shared_ or weak_ pointer. See the explanation at
http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/weak_ptr.htm for a more detailed argument of the same.
Thanks, no idea how I missed that. Makes perfect sense in threaded world but not convinced for single-threaded. If you don't want safety in your pointers,
then use raw pointers. If you want safety, then you have to accept the consequences...
So using get() on shared/scoped/auto/unique_ptr somehow keeps me safe having raw pointer that bypasses all protection they provide but weak_ptr is too much? Not buying it ;) Cheers, Simon

On Thursday, November 10, 2011 7:47 PM, Szymon Gatner wrote:
Because it is not safe to have a pointer to something and not reference count it.
Not sure what you mean here, I still have weak_ptr<> which has a counter and there is a shared_ptr<> (or not) somewhere out there. So counter exists as long as I still have any shared_ or weak_ pointer.
Not exactly. The weak_ptr reference counts an internal object, but not your object.
If you don't want safety in your pointers, then use raw pointers. If you want safety, then you have to accept the consequences...
So using get() on shared/scoped/auto/unique_ptr somehow keeps me safe having raw pointer that bypasses all protection they provide but weak_ptr is too much? Not buying it ;)
The difference is that, for shared/scoped/auto/unique_ptr, you can ensure the raw pointer remains valid by not destroying the smart pointer. Of course, it is your responsibility to keep that smart pointer around for as long as you use the raw pointer. However, a weak_ptr doesn't do anything to keep the underlying object around, and so keeping the weak_ptr doesn't guarantee the raw pointer remains valid. (from original post)
get() would return raw pointer from shared counter (so is fast) and not shared_ptr<> as lock() does.
Has a profiler (like Valgrind or VTune) verified the lock call significantly harms your performance?

After re-reading your reply, I think your confusion comes from the following idea: "I still have weak_ptr<> which has a counter ". A line from the weat_ptr<> documentation states that "When the last *shared_ptr* to the object goes away and the object is deleted, the attempt to obtain a *shared_ptr* from the *weak_ptr* instances that refer to the deleted object will fail". So, weak_ptr does not have a counter, that's it's weakness ;) I assume that clears things up for you. Since I had already typed a longer response walking through my mental journey, I'll leave it attached below in case it's of use to anyone else... -Tim Honestly, I'm pretty new to Boost and forgot about get_pointer() :) After being reminded of it, I originally agreed that if you're going to break reference counting at that level, you might as well break it everywhere. What started confusing me is why such an easy mechanism was made to bypass reference counting in the first place. I read http://www.boost.org/doc/libs/1_47_0/libs/bind/mem_fn.html and while I don't really understand the need for certain utility functions to get a raw pointer from a smart pointer, they obviously wanted a common interface for retrieving a raw pointer from any smart pointer class, even non-Boost ones. So, what makes sense to me now is that raw pointers should not be used willy-nilly. They should only be used in utility functions that really need them, and the intent is that *the raw pointer must be scoped by the use of a smart, reference counted, pointer*. If that's true (and I hope someone can verify), then it makes sense that weak_ptr would not be allowed to return a raw pointer (because weak_ptr is not reference counted). It seems to me, though, that get_pointer() is too exposed and thus easily abused. It would be nice to at least see the documentation beefed up to better clarify its intended usage and dangers. On 11/10/2011 7:46 PM, Szymon Gatner wrote:
Because it is not safe to have a pointer to something and not reference count it. Not sure what you mean here, I still have weak_ptr<> which has a counter and there is a shared_ptr<> (or not) somewhere out there. So counter exists as long as I still have any shared_ or weak_ pointer.
See the explanation at
http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/weak_ptr.htm for a more detailed argument of the same. Thanks, no idea how I missed that. Makes perfect sense in threaded world but not convinced for single-threaded.
If you don't want safety in your pointers,
then use raw pointers. If you want safety, then you have to accept the consequences... So using get() on shared/scoped/auto/unique_ptr somehow keeps me safe having raw pointer that bypasses all protection they provide but weak_ptr is too much? Not buying it ;)
Cheers, Simon _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

2011/11/11 Tim Musson
After re-reading your reply, I think your confusion comes from the following idea: "I still have weak_ptr<> which has a counter ". A line from the weat_ptr<> documentation states that "When the last shared_ptr to the object goes away and the object is deleted, the attempt to obtain a shared_ptr from the weak_ptr instances that refer to the deleted object will fail". So, weak_ptr does not have a counter, that's it's weakness ;)
I don't think I am the one that is confused. When last shared_ptr<> goes out of scope, weak_ptrs know that original object has expired - that is its purpose and its strength not a weakness. It knows that it has expired (has refcount == 0) because it still has access to the counter. It knows it is zero, it knows object has been deleted. Counter is not deleted as long as any weak_ptr<> exist (weakcount > 0) otherwise every weak_ptr<> would be useless after last shared_ptr<> been destroyed. To clarify: weak_ptr<> does not increase/decrease refcount and does not affect object lifetime but it does affect weakcount and counter's lifetime.
I assume that clears things up for you.
ditto Security concerns make little sense for me. Calling get() to obtain raw pointer is as dangerous with weak_ptr<> as with any other smart pointer. Moreover, auto/scoped/unique_ptr can be reset() (or moved) from other thread and screw things up as easily and no one complains. On the second thought on weak_ptr's rationale with regards of thread-safety, what about this: if (!weak.expired()) { // here it can expire from other thread weak.lock()->thisWillCauseAssert(); } Isn't this how weak_ptr<> is suppose to be used? /Simon

Szymon Gatner wrote:
On the second thought on weak_ptr's rationale with regards of thread-safety, what about this:
if (!weak.expired()) { // here it can expire from other thread weak.lock()->thisWillCauseAssert(); }
Isn't this how weak_ptr<> is suppose to be used?
No, it isn't. if( shared_ptr<> p = weak.lock() ) { p->thisWillNotAssert(); } expired() should only be used for positive tests: if( weak.expired() ). Once a weak_ptr expires, it stays expired, so there is no potential for a race.

No, it isn't.
if( shared_ptr<> p = weak.lock() ) { p->thisWillNotAssert(); }
expired() should only be used for positive tests: if( weak.expired() ). Once a weak_ptr expires, it stays expired, so there is no potential for a race.
So that is a "no" on a get() thing? ;) Regards, Simon

Szymon Gatner wrote:
No, it isn't.
if( shared_ptr<> p = weak.lock() ) { p->thisWillNotAssert(); }
expired() should only be used for positive tests: if( weak.expired() ). Once a weak_ptr expires, it stays expired, so there is no potential for a race.
So that is a "no" on a get() thing? ;)
It is a no. The removal of get() was intentional.

on Fri Nov 11 2011, Tim Musson
After re-reading your reply, I think your confusion comes from the following idea: "I still have weak_ptr<> which has a counter ". A line from the weat_ptr<> documentation states that "When the last shared_ptr to the object goes away and the object is deleted, the attempt to obtain a shared_ptr from the weak_ptr instances that refer to the deleted object will fail". So, weak_ptr does not have a counter,
Oh, but it does. There's a separate counter that counts related weak pointers even after the "strong" refcount goes to zero. Whether or not that has any relevance here, I don't know. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On 11/10/11 7:20 PM, Szymon Gatner wrote:
Hi,
Why weak_ptr does not have (smart) pointer semantics? No * or -> or even get().
I often need a pointer type that is a listener to shared_ptr<> (does not affect refcount) but is still usable as a regular pointer type. If providing * and -> operators is for some reason undesirable then just a get() member would be nice as it would allow to implement own wrapper with pointer semantics. get() would return raw pointer from shared counter (so is fast) and not shared_ptr<> as lock() does.
I think the issue is that without converting the weak_ptr to a shared_ptr, you don't have any way to make sure that the object pointed to by the weak_ptr hasn't gone away (especially in a multi-threaded application). -- Richard Damon
participants (6)
-
Andrew Holden
-
Dave Abrahams
-
Peter Dimov
-
Richard Damon
-
Szymon Gatner
-
Tim Musson