The cpp reference has this example of how to use std::enable_shared_from_this
(slightly adjusted)
class Good : std::enable_shared_from_this<Good>
{
public: std::shared_ptr<Good> getptr() { return shared_from_this(); }
};
...
auto good = std::make_shared<Good>();
good->getptr();
However, this does NOT work in Visual Studio 2015 (Enterprise, Version 14.0.25123.00 Update 2), i.e. a std::bad_weak_ptr
exception is thrown.
Looking at other examples (including different ones from cpp reference or Microsoft) I noticed that they use public
inheritance instead of private
one. And using public
inheritance actually solves my problem (no std::bad_weak_ptr
anymore but a valid shared_ptr
instead).
Cpp reference does not mention that I have to publicly inherit from std::enable_shared_from_this
, so where is the error? Is Visual Studio's behavior wrong (I guess there is a visibility problem when using private
inheritance) or did cpp reference fail to mention this limitation?
PS: make_shared<good>()
or shared_ptr<Good>(new Good)
doesn't make a difference.
PSS: Both versions compile just fine, the private one just doesn't work, making this a quite nasty kind of bug.
EDIT: Changed struct
to class
. Cpp reference actually uses public inheritance in its examples. Still, no word that it has to be public. It is actually listed there, I just have to learn to read carefully. Thanks @Angew.
A typical implementation of std::enable_shared_from_this
, requires the std::shared_ptr
constructor (called by std::make_shared
in your case) to be able to detect the presence of a std::enable_shared_from_this
base, so it can set the std::weak_ptr
member of that base.
With private inheritance, that's not possible, so you get the runtime exception you got when calling shared_from_this
(because the std::weak_ptr
was never set, since the std::shared_ptr
constructor couldn't detect the std::enable_shared_from_this
base).
The C++ standard mentions such an implementation :
[ Note: A possible implementation is shown below:
template<class T> class enable_shared_from_this { private: weak_ptr<T> __weak_this; protected: constexpr enable_shared_from_this() : __weak_this() { } enable_shared_from_this(enable_shared_from_this const &) { } enable_shared_from_this& operator=(enable_shared_from_this const &) { return *this; } ~enable_shared_from_this() { } public: shared_ptr<T> shared_from_this() { return shared_ptr<T>(__weak_this); } shared_ptr<T const> shared_from_this() const { return shared_ptr<T const>(__weak_this); } };
The
shared_ptr
constructors that create unique pointers can detect the presence of anenable_shared_from_this
base and assign the newly createdshared_ptr
to its__weak_this
member. — end note ]
The cppreference page you linked to also mentions this in the notes.
The code in your question doesn't use private inheritance at all: struct
defaults to public access control, both for members and for base classes.
Furthermore, cppreference does not omit anything. The text of the page clearly states:
Publicly inheriting from
std::enable_shared_from_this<T>
...
(Emphasis mine)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With