46

In my current project I am using boost::shared_ptr quite extensively.

Recently my fellow team mates have also started using weak_ptr. I don't know which one to use and when.

Apart from this, what should I do if I want to convert weak_ptr to shared_ptr. Does putting a lock on weak_ptr to create a shared_ptr affect my code in other thread?

fduff
  • 3,671
  • 2
  • 30
  • 39
RLT
  • 4,219
  • 4
  • 37
  • 91

4 Answers4

71

In general and summary,

Strong pointers guarantee their own validity. Use them, for example, when:

  • You own the object being pointed at; you create it and destroy it
  • You do not have defined behavior if the object doesn't exist
  • You need to enforce that the object exists.

Weak pointers guarantee knowing their own validity. Use them, for example, when:

  • You access it, but it's not yours.
  • You have defined behavior if the object doesn't exist

Lock() on a weak pointer returns a strong pointer; this is how you access the weak pointer. If the object is no longer valid (it's been deleted, etc), then the strong pointer will be NULL, otherwise, it will point at the object. You will need to check this.

It's set up this way so that you cannot accidentally delete the object while you're using it, because you've made a temporary (local) strong pointer, and thus garunteed the object's existence while that strong pointer remains. When you're done using the object, you generally let the strong pointer fall out of scope (or reassigning it), which then allows the object to be deleted. For multithreading, treat them with same care you treat other things that don't have built-in thread safety, noting that the guarantee I mentioned above will hold when multithreading. AFAIK they don't do anything special past that.

The boost shared pointers also have garbage-collector like features, since when the last strong pointer to an object goes away or points somewhere else, the object gets deleted.

There's also the performance and circular dependencies mentioned in the other answers.

Fundamentally, I would say that the boost shared pointer library allows you to not mess up putting together a program, but it is no substitute for taking the time to properly design your pointers, object ownerships and lifetimes. If you have such a design, you can use the library to enforce it. If you don't have such a design, you're likely to run into different problems than before.

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Narfanator
  • 5,595
  • 3
  • 39
  • 71
23

Use weak_ptr when the objects you create contain cyclical references, i.e. shared_ptr to an object with a shared_ptr back to yourself. This is because shared_ptr cannot handle cyclical references - when both objects go out of scope, the mutual referencing means that they are not "garbage collected", so the memory is lost and you have a memory leak. Since weak_ptr does not increase the reference count, the cyclical reference problem does not occur. This also means in general that if you just want to take a pointer to something that is reference counted and do not want to increase its reference count, then use weak_ptr.

Otherwise, you can use shared_ptr.

For more information, check the Boost documentation.

hackjutsu
  • 8,336
  • 13
  • 47
  • 87
blwy10
  • 4,862
  • 2
  • 24
  • 23
  • 1
    That's wrong, and even absurd. When you need ownership, use a owning (strong) smart pointer. When you want to be able to get a strong pointer if the object still exists, and nothing if it has been destructed, use a weak pointer. Narfanator explained all that perfectly. If you have cycles, you cannot use either. – curiousguy Oct 07 '11 at 14:54
  • 2
    @curiousguy http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/shared_ptr.htm 'Use weak_ptr to "break cycles."' So yes, you can use a weak pointer when you have cycles. Also, the OP asked about shared_ptr and weak_ptr, so reason would suggest it would be alright to neglect mentioning scoped_ptr. Otherwise, I just said you CAN use shared_ptr, not that you must or that it is your only option, nor did I give inaccurate information about it (I didn't even give any information), and I even linked the documentation. What's "wrong" or "absurd" about that? – blwy10 Oct 07 '11 at 15:28
  • @curiousguy And I'm not disagreeing with you that Narfanator's explanation is correct - I only answered before he did anyway. – blwy10 Oct 07 '11 at 15:29
  • "_Use weak_ptr to "break cycles_" That's ridiculous. **There is a cycle or there isn't.** weak_ptr does not "break" cycles, **you** define the cycle out of existence. "_nor did I give inaccurate information about it (I didn't even give any information), and I even linked the documentation._" If the doc supports your point of view (I didn't read it), then the doc is crazy. – curiousguy Oct 07 '11 at 15:41
  • 4
    @curiousguy That's just semantics then. Defining the cycle out of existence, i.e. there is still a cycle of pointers, but one edge of the cycle is a weak_ptr reference, is breaking the cycle! So you've conceded that weak_ptr can be used when there is a cycle, just that in your terms the cycle ceases to exist, which is just what I said worded differently. – blwy10 Oct 11 '11 at 16:18
  • @curiousguy And one other thing I noticed. In your first comment you support Narfanator's explanation, and yet you deny weak_ptr's involvement with breaking cycles, when in fact he also mentions that "circular dependencies" i.e. cycles in object referencing, i.e. the cycles in question here are also applicable cases for use of weak_ptr. That would mean one of: you did not read his answer in full, or did not understand his answer in full, or did not understand my answer in full. – blwy10 Oct 11 '11 at 21:11
  • "_So you've conceded_" No I haven't "conceded" anything. Stop being silly. "_just that in your terms the cycle ceases to exist_" If your "cycle" has a weak reference, obviously it is NOT the cycle of strong references that existed previously. – curiousguy Oct 14 '11 at 03:20
  • "_In your first comment you support Narfanator's explanation_" Indeed! "_yet you deny weak_ptr's involvement with breaking cycles_" Exactly. **The removal of `shared_ptr` by the programmer breaks the cycle.** `weak_ptr` does nothing here. "_That would mean one of: you did not read his answer in full, or did not understand his answer in full_" Obviously I did read AND I understand his answer. "_or did not understand my answer in full._" Or you don't even understand what you are writing. – curiousguy Oct 14 '11 at 03:23
  • "_Defining the cycle out of existence, i.e. there is still a cycle of pointers, but one edge of the cycle is a weak_ptr reference, is breaking the cycle! So you've conceded that weak_ptr can be used when there is a cycle_" And when I have a division-by-zero error, I can remove the division-by-zero and add some `weak_ptr` for fun. Then I have fixed a division-by-zero with a `weak_ptr`. – curiousguy Oct 14 '11 at 03:36
  • _If your "cycle" has a weak reference, obviously it is NOT the cycle of strong references that existed previously._ But no one said it was a cycle of strong references - we just said if there is a cycle of references, you cannot use shared_ptr at both points, one point must be a weak_ptr, i.e. breaking the cycle, and using it when there is a cycle **of references**, not **strong references**. – blwy10 Oct 14 '11 at 07:25
  • I think you misunderstand stand me - what I meant is this: You agree with Narfanator, and Narfanator and I have the same thing to say about cyclic references/circular dependencies - use weak_ptr as one of your pointer in the cycle to break the cycle, and yet you completely deny any shred of truth in what I say - this is clearly a contradiction - you cannot reasonably hold these 3 things. And Narfanator and I are saying the same things about cyclic references - he specifically agreed with the _other_ answers about cyclic dependencies, i.e. mine included. – blwy10 Oct 14 '11 at 07:28
  • Lastly, you are clearly conceding. You first say that _If you have cycles, you cannot use either._, and then you say that when a "cycle" has a weak_ptr and a shared_ptr it is not a cycle. Either you were trying to make a small semantic point that cycles cease to exist when there is a weak_ptr, which is purely semantic and contingent on a particular reading of the word cycle, of which my reading is equally legitimate, or you were trying to make the point that when in general there is a cycle of references, weak_ptr can never be used, which you have clearly backtracked from. – blwy10 Oct 14 '11 at 07:32
  • Reading your other answers/comments on SO suggests your specific gripe is that it ceases to be a dependency - so fine I'll happily give you that the cycle no longer exists in the sense of a cycle of dependencies. But it is still a cycle of references, which is what my answer is amount. It's because 2 objects are still **refer**ring to each other, hence cyclic reference. Sure you don't need a weak_ptr, just like you don't need smart ptr, but if you want to use a smart ptr, you need weak_ptr. – blwy10 Oct 14 '11 at 07:41
  • "_there is a cycle of references, not strong references_" The unqualified word "reference" **always** means "strong reference". **A "weak reference" is not a reference**, it's an observer, as others have explained. – curiousguy Oct 14 '11 at 16:21
  • 1
    And why, pray tell, is that necessarily the definition of the unqualified word "reference"? – blwy10 Oct 14 '11 at 21:31
  • What is the referent of `weak_ptr`? can you access it? – curiousguy Dec 15 '11 at 05:28
  • The referent is the object pointed to by a shared_ptr. You can access it when you lock it, as the accepted answer says. If the object has been deleted, you cannot access it. So it has a referent, so it is a reference. Not a reference in a C++ language feature, but still a reference in some sense of the word "refer" – blwy10 Dec 15 '11 at 11:55
  • You cannot access the referent until you have obtained a `shared_ptr`; `weak_ptr` is the "promise" of reference, it isn't one. – curiousguy Dec 16 '11 at 15:28
  • 4
    so who won this debate? – stewart99 Jan 13 '14 at 06:19
  • @doorfly `shared_ptr` and `weak_ptr` have different semantic, so one isn't a drop-in replacement for the other, and implicitly implying otherwise is dangerous. A reference (unqualified) has a reference which isn't going away without notice. A mutual dependency problem is fixed by redesign. Just like an infinite recursion problem. There are no magic answers. – curiousguy Jul 03 '16 at 07:23
7

Shared pointers implement reference counting, weak pointers do not affect reference counting and if you don't have shared pointers to an object, only weak pointers, the object gets deleted and the weak pointers now tell you that the object has been lost.

There are two reasons to use a weak pointer:

  1. To eliminate the cost of reference count increase / decrease; however you shouldn't do this because it is error-prone and doesn't really save much time
  2. In bookkeeping data structures, e.g. you have an index of all objects Foo that are "alive", i.e. used somewhere else, and you don't want to keep a Foo alive in the index if all the "real" uses have ended. This is the basic realistic use case for weak pointers. Of course others exist also.

So in general, my recommendation would be to use weak pointers only when you know that you want to let the referenced objects be deleted and want to detect that. In other cases use shared pointers (reference counting), or direct pointers, esp. in method local variables when you know that the objects are not going to get deleted. Also errorprone, though, but faster than shared pointers.

N.B. cyclical objects do not need weak pointers, you can use non-cooked, regular pointers instead in most properly constructed programs. Weak pointers less risky, though.

Antti Huima
  • 25,136
  • 3
  • 52
  • 71
  • @Trent well actually there isn't, it was a typo---it was first two, then I edited it to "three" to accommodate the other answer's comment about cyclical structures, but I started to wonder why because that's not what weak pointers are for in garbage collected languages, and then I realized that you don't need 'em, so I erased it and added the N.B. Of course you can use 'em but they're just basically a type of assert, you don't need 'em for cyclical objects – Antti Huima Jan 10 '10 at 06:01
  • Weak pointers do affect reference counting - shared_ptr implementations need to keep separate strong and weak refcounts for reasons too complex to get into for a comment. weak_ptr is to break cycles, end of story. – Terry Mahaffey Jan 10 '10 at 08:05
  • 1
    It's getting religious. But weak pointers exist also in properly garbage collected languages. The weak pointer concept is not related originally to cycles, but to detecting that the object behind has been deleted by the resource manager (e.g. reference counting, garbage collecting, etc.) – Antti Huima Jan 11 '10 at 07:22
  • 2
    I don't want to get religious, but I don't think it is safe to use raw pointers to memory held in smart pointers, see my [answer](http://stackoverflow.com/questions/7011877/shared-ptr-and-logical-pointer-ownership-use-case-in-a-complex-design/7020466#7020466) to a different question. – Rasmus Storjohann Aug 21 '11 at 01:04
  • "_There are two reasons to use a weak pointer_" That is just wrong. **You either need a strong reference or you do not.** You do not get to choose between weak or strong reference, it is imposed by the design constraints. – curiousguy Oct 07 '11 at 15:25
  • @TerryMahaffey "_weak_ptr is to break cycles, end of story_" Preposterous. Either there is a cycle or there is no cycle. Weak reference is not a magic wand that "breaks" cycles (whatever that means). – curiousguy Oct 07 '11 at 15:31
-10

You should probably not be trying to use weak pointers at all unless you are trying to implement a garbage collector, which is not a hot idea in C++ because it's too hard to keep track of everything that could go wrong closely enough.