Search code examples
c++smart-pointersweak-ptr

weak_ptr obtained from weak_from_this() is invalid


Here is a minimal example to reproduce:

source code:

#include <memory>
#include <iostream>

class A : public std::enable_shared_from_this<A>
{
 public:
  A(std::weak_ptr<A> up) : up_(up)
  {
    std::cout << "A" << " has up_? " <<
        ((up_.lock()) ? "yes" : "no")
              << std::endl;
  }

  void grow()
  {
    if (dp_)
      dp_->grow();
    else
      dp_ = std::make_shared<A>(weak_from_this());
  }

 private:
  std::weak_ptr<A> up_;
  std::shared_ptr<A> dp_;
};

int main()
{
  auto wp = std::weak_ptr<A>();
  A a(wp);
  for (int i = 0; i < 3; ++i)
  {
    a.grow();
  }
  return 0;
}

original log:

clang++ minimal.cpp && ./a.out
A has up_? no
A has up_? no
A has up_? yes
A has up_? yes

desired behavior:

clang++ minimal.cpp && ./a.out
A has up_? no
A has up_? yes
A has up_? yes
A has up_? yes

Actually I want to know why the second line in the original output says 'no'? I think when we create the object of type A for the first time, (precisely after its construction finishes, and before we call grow() on it), we have a valid object that we can pass references to to wherever we want, don't we?


Solution

  • From cppreference, about std::enable_shared_from_this::weak_from_this

    Returns a std::weak_ptr<T> that tracks ownership of *this by all existing std::shared_ptr that refer to *this.

    Meanwhile

    A a(wp);
    

    This is not an object that is tracked by any shared_ptr. It's a plain object with automatic storage duration. If you want weak_from_this to work, there must be a shared_ptr tracking the first object.