I have simple base and derived class that I want both have shared_from_this()
.
This simple solution:
class foo : public enable_shared_from_this<foo> {
void foo_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&foo::foo_do_it,shared_from_this());
}
virtual ~foo() {};
};
class bar1 : public foo , public enable_shared_from_this<bar1> {
using enable_shared_from_this<bar1>::shared_from_this;
void bar1_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&bar1::bar1_do_it,shared_from_this());
}
};
Causes exception tr1::bad_weak_ptr
in following code:
shared_ptr<foo> ptr(shared_ptr<foo>(new bar1));
function<void()> f=ptr->get_callback();
f();
So after "googling" I have found following solution:
class bar2 : public foo {
void bar2_do_it()
{
cout<<"foo::do_it\n";
}
shared_ptr<bar2> shared_from_this()
{
return boost::static_pointer_cast<bar2>(foo::shared_from_this());
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&bar2::bar2_do_it,shared_from_this());
}
};
And now it works.
Is there any better and more convinient and correct way to enable_shared_from_this
for both parent and child?
Thanks
The OP solution can be made more convenient by defining the following on the base class.
Sorry, but there isn't.
The problem is that
shared_ptr<foo>
andshared_ptr<bar1>
are different types. I don't understand everything that's going on under the hood, but I think that when the constructor returns and is assigned to ashared_ptr<foo>
, the internalweak_ptr<bar1>
sees that nothing is pointing to it (because only ashared_ptr<bar1>
would increment the counter) and resets itself. When you callbar1::shared_from_this
inget_callback
, you get the exception because the internalweak_ptr
isn't pointing to anything.Essentially,
enable_shared_from_this
only seems to work transparently from a single class in a hierarchy. If you try implementing it manually, the problem should become obvious.A similar solution to @evoskuil that reduces boilerplate in derived classes should you want to implement a
shared_from_this()
function, resulting in the following code at the point of use in the class:This uses 'shim' functions outside of the class. By doing it that way it also provides a clean way to do this for classes who's interface can't be modified but derive from
enable_shared_from_this
- e.g.Note: Use of
auto
for return types here will depend upon the age of your compiler.Shim functions that could be placed in a library header:
The above code relies on the fact that the type passed to
shared_from(...)
inherits fromstd::enable_shared_from_this<Base>
at some point in its ancestry.Calling
shared_from_base
will figure out what type that ultimately was. Since we know thatThat
inherits fromBase
, a static downcast can be made.Probably there are some pathological corner cases with classes having type conversion operators.. but that's unlikely to occur in code not designed to break this.
Example:
Compilation test:
https://onlinegdb.com/SJWM5CYIG
Prior solution that I posted, kept to make the comments still make sense - this placed the functions in the base class which had some problems - particularly non-uniformity between the required implementation for 'normal' classes and template classes.
Additionally the implementation in the base class would need to be repeated for new class hierarchies which is not all that DRY. Furthermore the base class function suffered from the possibility of misuse by supplying a base class pointer from a different object. The newer scheme above avoids this entirely and the runtime assert(...) check goes.
Old implementation: