I am writing a class that should derive from an abstract base class. I cannot change the abstract base class. The class will be held as a shared_ptr
to the abstract base class. Is it OK to inherit from the abstract base class and enable_shared_from_this
? Like this:
class IWidget {
public:
virtual ~IWidget(){}
// ...
};
class Widget : public std::enable_shared_from_this<Widget>, public IWidget {
protected:
Widget(); // protected, use create
public:
static std::shared_ptr<IWidget> create() {
return std::shared_ptr<IWidget>(new Widget(init));
}
// ...
};
More complete code here that seems to work.
Most of the examples I can find of enable_shared_from_this
have it on the base class. In this case I can't change the base class. Is it OK to use multiple inheritance and use it on the derived class?
I was a bit worried that I could only guarantee enable_shared_from_this
would only work if I created a shared_ptr<Widget>
but in this case I'm creating a shared_ptr<IWidget>
.
Update: One interesting thing I noticed is that if I change the create
method to:
IWidget* w = new Widget(init);
return std::shared_ptr<IWidget>(w);
I get a runtime error when I try and use shared_from_this()
. I think this makes sense. shared_ptr
has a templated constructor that takes a "convertible" pointer. And unless the shared_ptr
constructor knows it is taking a Widget
it doesn't know it derives from enable_shared_from_this
and it can't store a weak_ptr
. I just wonder if this behaviour is documented.
Yes, it's absolutely fine.
shared_ptr
has a templated constructor that takes a "convertible" pointer. And unless theshared_ptr
constructor knows it is taking aWidget
it doesn't know it derives fromenable_shared_from_this
and it can't store aweak_ptr
.
Exactly right.
I just wonder if this behaviour is documented.
In the current standard enable_shared_from_this
is very poorly specified, but see P0033 for the new and improved specification of enable_shared_from_this
which will be in C++17. As well as answering the "what happens if you do it twice?" question, the revised wording specifies exactly how the enable_shared_from_this
base class is used, and how the weak_ptr
member is initialized. That part of the new wording is just standardising existing practice, i.e. it is just a more accurate description of what real implementations already do. (The answer to the "what happens if you do it twice?" question deviates from what implementations previously did, but for good reasons, and that isn't relevant to your question anyway).
The new spec clarifies that your original example is entirely well-defined and correct.
The current standard says that the modified version in your updated question has undefined behaviour when you call shared_from_this()
, due to violating the precondition that there is shared_ptr
that owns the pointer-to-derived (because you create a shared_ptr
that owns the pointer-to-base). However, that precondition is not sufficient to ensure sensible semantics, as explained in the paper. The revised wording makes your modified version also well-defined (i.e. no undefined behaviour) but the weak_ptr
in the base class will not share ownership with the shared_ptr<IWidget>
and so shared_from_this()
will throw an exception (which is what you observe from your implementation).
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