Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will move from unique to shared pointer also initialize enable_shared_from_this

When I inherit from std::enable_shared_from_this, but I create a unique_ptr, will the weak_ptr inside std::enable_shared_from_this also be initialized when I "move" to a shared_ptr by std::move, or by the move constructor?

For example what will happen in the below code:

#include <memory>
#include <iostream>

class A : public std::enable_shared_from_this< A >
{
public:
    std::shared_ptr< A > getA()
    {
        return shared_from_this();
    }
};

int main()
{
    std::unique_ptr< A > u(new A());
    // Aborts
    //std::cout << u->getA() << std::endl;
    std::shared_ptr< A > s(std::move(u));
    // Will this work or abort too?
    std::cout << s << ", " << s->getA() << std::endl;
}
like image 229
HankTheTank Avatar asked Jan 28 '23 00:01

HankTheTank


2 Answers

According to https://en.cppreference.com/w/cpp/memory/enable_shared_from_this all the std::shared_ptr constructors should initialise the internal weak reference so moving a std::unique_ptr into a std::shared_ptr should enable the use of shared_from_this.

You do have to be careful that nobody calls shared_from_this whilst the object is owned by std::unique_ptr as that is either undefined behaviour or will throw std::bad_weak_ptr depending on your c++ version.

like image 166
Alan Birtles Avatar answered Feb 16 '23 02:02

Alan Birtles


[util.smartptr.shared.const]/1 In the constructor definitions below, enables shared_from_this with p, for a pointer p of type Y*, means that if Y has an unambiguous and accessible base class that is a specialization of enable_shared_from_this (23.11.2.5), then remove_cv_t<Y>* shall be implicitly convertible to T* and the constructor evaluates the statement:

if (p != nullptr && p->weak_this.expired())
p->weak_this = shared_ptr<remove_cv_t<Y>>(*this, const_cast<remove_cv_t<Y>*>(p));

template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);

[util.smartptr.shared.const]/29 Effects: ... equivalent to shared_ptr(r.release(), r.get_deleter())


template<class Y, class D> shared_ptr(Y* p, D d);

[util.smartptr.shared.const]/10 Effects: Constructs a shared_ptr object that owns the object p and the deleter d. When T is not an array type, ... enable shared_from_this with p

So yes, std::shared_ptr< A > s(std::move(u)); does initialize things appropriately to make shared_from_this work.

like image 32
Igor Tandetnik Avatar answered Feb 16 '23 03:02

Igor Tandetnik