c++shared-ptrunique-ptrweak-ptrenable-shared-from-this

Empty weak pointer in enable_shared_from_this


After publicly inheriting enable_shared_from_this and initialzing the object of class, while calling another function of that class, i can still see empty weak pointer of enable_shared_from_this_class while debugging in Visual Studio.

All existing questions are due to either privately inheriting from enable_shared_from_this or calling weak_from_this in constructor. This is not the case for me. I am currently using c++ catch framework to test this scenario in visual studio debugger. In Initialize function, i can see, that weak_ptr of this object is empty.

header File :


template <typename T>
class IInfo
public:
IInfo()
    {}
    virtual ~IInfo()
    {}
    virtual bool RegisterForChange(FUNC_PTR<T> Callback, std::weak_ptr<T>) = 0;
};

template <typename T>
class Info : public IInfo<T>, public std::enable_shared_from_this<Info<T>>
{
public:
    Info() {}
    ~Info() {}
    virtual bool RegisterForChange(FUNC_PTR<T> Callback, std::weak_ptr<T> callerContext) override
    {
        //Some code
        _callerContext = callerContext;
    }
private:
    std::weak_ptr<T> _callerContext;
};


class Env : public std::enable_shared_from_this<Env>
{
public:
    Env();
    bool Initialize();
    static void func(/ some arguments / );
private:
    std::shared_ptr<Info<Env>>_spInfo;
    //other variables
}

Cpp File :

Env::Env() : _spInfo() // + other variables in initializer list
{
    _spInfo = std::make_shared<Info<Env>>();
}

bool Env::Initialize()
{
    _spInfo->RegisterForChange(FUNC_PTR<Env>func, this->weak_from_this());
}

TEST CASE : (used cpp catch framework)

Env env;
env.Initialize();

EDIT: As per comments , asking it correcty, the Env module will be managed by a plugin which will create a unique_ptr and call Initialize. Something like:

    template<typename T>
    std::unique_ptr<T> BringUp()
    {
        std::unique_ptr<T> ptr(std::make_unique<T>());
        if (ptr && ptr->Initialize())
            return std::move(ptr);
    }

std::unique_ptr<Env> _envPtr;
_envPtr = BringUp<Env>();

I still face the same issue. How shall i manage Env in this case?


Solution

  • Your construction code is still wrong. For shared_from_this to work, the object's lifetime has to be managed by shared pointers. First you tried managing it by scope and then you tried managing it with a unique pointer. Neither of those will work.

    The point of shared_from_this is to allow an object's lifetime to be extended by code that needs to extend it. For that to work, the object's lifetime has to be managed by some structure that makes it possible for objects to extend its life. A scope can't do that because when the scope ends the object's memory is released. A unique_ptr can't do that because only one pointer to the object can exist at any time, so there's no way to extend its life as that would require two pointers (one would have to already exist or it would be dead and the one extending its life would be another).

    Construct the Env object using std::make_shared and store a std::shared_ptr to it.

        template<typename T>
        std::shared_ptr<T> BringUp()
        {
            std::shared_ptr<T> ptr(std::make_shared<T>());
            if (ptr && ptr->Initialize())
                return std::move(ptr);
        }
    
    std::shared_ptr<Env> _envPtr;
    _envPtr = BringUp<Env>();