Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

shared_from_this has empty _M_weak_this even after ownership by std::shared_ptr

I'm storing a class (let's call it A) in an std::vector using C++ smart pointers (so the vector sigature is std::vector<std::shared_ptr<A>>).

#include <iostream>
#include <memory>
#include <vector>

class A : std::enable_shared_from_this<A> {
public:
  void doWork();
  std::shared_ptr<A> getSharedRef();
};

void A::doWork() { std::cout << "Working..." << std::endl; }

std::shared_ptr<A> A::getSharedRef() { return shared_from_this(); }

class AManager {
  static std::vector<std::shared_ptr<A>> aList;

public:
  static void init(); // safety because statics
  static void doLotsOfWork();
  static std::shared_ptr<A> createA();
};

std::vector<std::shared_ptr<A>> AManager::aList;

void AManager::init() { aList = std::vector<std::shared_ptr<A>>{}; }

void AManager::doLotsOfWork() {
  for (auto a : aList) {
    a->doWork();
  }
}

std::shared_ptr<A> AManager::createA() {
  std::shared_ptr<A> a = std::make_shared<A>();

  aList.push_back(a);
  return a->getSharedRef(); // <----- EXCEPTION
}

int main() {
  AManager::init();
  AManager::createA();
  return 0;
}

For some reason, this throws a std::bad_weak_ptr, and upon inspection I notice that a, for whatever reason, has an _M_weak_this equal to 0x0, or NULL. Since I've already created a valid std::shared_ptr referencing the object, it shouldn't be empty.

Furthermore, I know no memory corruption is occurring because A (with variables) is completely intact at its address.

What am I doing wrong?

like image 784
iikorni Avatar asked Dec 12 '17 12:12

iikorni


1 Answers

The problem appears to be because you are inheriting privately from enable_shared_from_this

shared_from_this requires "enable_shared_from_this<T> shall be an accessible base class of T." (according to [util.smartptr.enab])

By inheriting privately, the base class is not accessible, and so the preconditions are violated. I presume this means undefined behavior. Both Clang and GCC throw an exception.

The solution is to inherit publicly.

class A :  public std::enable_shared_from_this<A> {
    //...
};

*In C++17 the wording appears to have moved to [util.smartptr.shared.const], but the requirement is basically the same.

like image 127
AndyG Avatar answered Sep 19 '22 02:09

AndyG