enable_shared_from_this initializes an empty weak ptr so how does it work its magic?

enable_shared_from_this creates a shared_ptr from an empty weak ptr. This makes no sense to me - I would have thought that the weak ptr should be initialized with this instead; that makes sense...

So how does this class create a shared_ptr from this if it bases the shared_ptr on an empty weak_ptr?

Am I clear?

My guess is that this empty weak_ptr is exacly what makes it work, but why?
Last edited on
Why do you think an empty weak pointer is involved? Show an example.
enable_shared_from_this effectively has a mutable weak_ptr as a member sub-object. The weak_ptr is initially empty, but it doesn't usually stay that way.

x.shared_from_this() requires that a shared_ptr to x exists before it is called. The requirement is necessary because the weak_ptr is set up by the shared_ptr constructor. It is this first shared_ptr that allocates the control structures.

For example
1
2
3
4
5
6
7
8
#include <memory>
struct A : std::enable_shared_from_this<A> {}; 
int main()
{ 
  auto pa = new A;
  auto s1 = std::shared_ptr<A>(pa);
  auto s2 = pa->shared_from_this();
}

After line 6 *pa's internal weak_ptr is no longer empty.
Without line 6 line 7 would throw bad_weak_ptr.
Last edited on
@dutch the implementation of shared_pointer_from_this is (in Windows MS VS):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// CLASS TEMPLATE enable_shared_from_this
template <class _Ty>
class enable_shared_from_this { // provide member functions that create shared_ptr to this
public:
    using _Esft_type = enable_shared_from_this;

    _NODISCARD shared_ptr<_Ty> shared_from_this() {
        return shared_ptr<_Ty>(_Wptr);
    }

    _NODISCARD shared_ptr<const _Ty> shared_from_this() const {
        return shared_ptr<const _Ty>(_Wptr);
    }

    _NODISCARD weak_ptr<_Ty> weak_from_this() noexcept {
        return _Wptr;
    }

    _NODISCARD weak_ptr<const _Ty> weak_from_this() const noexcept {
        return _Wptr;
    }

protected:
    constexpr enable_shared_from_this() noexcept : _Wptr() {}

    enable_shared_from_this(const enable_shared_from_this&) noexcept : _Wptr() {
        // construct (must value-initialize _Wptr)
    }

    enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept { // assign (must not change _Wptr)
        return *this;
    }

    ~enable_shared_from_this() = default;

private:
    template <class _Yty>
    friend class shared_ptr;

    mutable weak_ptr<_Ty> _Wptr;
};


See it is initialized empty?

Now, how does line 6 of @mbozzi code set the internal _Wptr to own this (A)?

s1 is a shared_ptr over all A but not its data member _Wptr... or how is _Wptr affected by the creation of a shared_ptr of A?
> how does line 6 of @mbozzi code set the internal _Wptr to own this (A)?

The shared pointer is a friend. lines 37, 38: template < class Y > friend class shared_ptr;

The constructor of the shared pointer, given a pointer U*
determines if U has an unambiguous and accessible base class that is a specialization of std::enable_shared_from_this, and if so, the constructor evaluates the statement:
1
2
3
if (ptr != nullptr && ptr->weak_this.expired())
  ptr->weak_this = std::shared_ptr<std::remove_cv_t<U>>(*this,
                                  const_cast<std::remove_cv_t<U>*>(ptr));

Where weak_this is the hidden mutable std::weak_ptr member of std::shared_from_this.
https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr#Notes
Last edited on
The friend declaration on lines 36 and 37 confer shared_ptr access to _Wptr.
https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr#Notes
Thank you so much!!
Both @mbozzi and @JLBorges!! It is clear now
Topic archived. No new replies allowed.