1

Taking a look at std::weak_ptr I have seen in a couple of places that it can be used to break memory leaks due to circular dependencies using std::shared_ptr. See for example these two accepted answers: [1], [2].

Taking the last referenced answer, the proposed fix is:

#include <memory>
#include <iostream>

struct B;
struct A {
  std::shared_ptr<B> b;  
  ~A() { std::cout << "~A()\n"; }
};

struct B {
  std::weak_ptr<A> a;
  ~B() { std::cout << "~B()\n"; }  
};

void useAnB() {
  auto a = std::make_shared<A>();
  auto b = std::make_shared<B>();
  a->b = b;
  b->a = a;
}

int main() {
   useAnB();
   std::cout << "Finished using A and B\n";
}

This feels like an overkill, though, why not simply use a reference? I understand that in this example b->a is not set in the constructor so a reference would not really cut it, so my question is:

Is there a reason to use a std::weak_ptr instead of a reference if the point is to break circular dependency if we can set it in the constructor?

NOTE: I understand the usefulness of std::weak_ptr to hold a reference that can be invalidated. My question only concerns the usefulness when the point is exclusively to break circular dependency.

user2891462
  • 3,033
  • 2
  • 32
  • 60
  • 1
    There are indeed more then one way to break circular dependencies. Using shared and weak pointers are more a question of ownership. Who owns, in this case, A and B. – super Jul 03 '18 at 11:18
  • To make the question more focused, you could compare a reference and a constant non owning smart ptr (not smart ptr to const). – curiousguy Jul 08 '18 at 23:56

3 Answers3

1

Here's a slightly modified function:

void useAnB() {
  std::shared_ptr<B> oops;
  {
      auto a = std::make_shared<A>();
      auto b = std::make_shared<B>();
      a->b = b;
      b->a = a;
      oops = b;
  }
  // use oops->a 
}

How could you know that oops->a no longer refers to a valid object if it was a plain pointer or reference?

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • I can see the usefulness of `std::weak_ptr` when dealing with "unvalidatable" references, as a solution to the dangling pointer problem. My question is about its usefulness when the point is to break circular dependency. – user2891462 Jul 03 '18 at 11:12
  • 2
    @user2891462 - It begs the question of why one would use a shared pointer if they don't have shared ownership. The preferred solution is a `weak_ptr` because it's future proof. Copies of shared pointer tend to pop up. If you were to use a `unique_ptr` then there really is no need to introduce overhead. A raw pointer would suffice. – StoryTeller - Unslander Monica Jul 03 '18 at 11:19
  • @StoryTeller It begs the question of why one would allow sharing to pop up and how that popping up is considered future proof. Do you have data structures that can be shared? Unless they are read only, I doubt it. – curiousguy Jul 09 '18 at 00:00
1

You can't check whether a reference (or plain pointer) refers to an existing object, and you can't "reseat" a reference, for instance in an assignment.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • Thanks for your answer. I have added a note to address this: I am aware of the usefulness of `std::weak_ptr` to deal with an "invalidatable" pointer, but my question is concerning a different use case: breaking circular dependency. – user2891462 Jul 03 '18 at 11:09
0

I understand the usefulness of std::weak_ptr to hold a reference that can be invalidated. My question only concerns the usefulness when the point is exclusively to break circular dependency.

Well, if you have a circular dependency (or even if you don't) and you want to store a reference to the 'master' object somewhere else so that you can access it, and you know for certain that that object is not going to go away while you might want to do that, then yes, I would just use a reference, because:

  • it's cheaper
  • it might avoid the need to make the master object a shared_ptr in the first place (and these in themselves are quite expensive)

It comes down, in the end, to desiging your objects to best perform whatever job it is you need them to do. Certainly, std::weak_ptr is not the answer to every maiden's prayer.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48