Search code examples
c++referencesmart-pointersweak-ptr

Plain reference instead of weak_ptr to break circular dependency


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.


Solution

  • 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?