Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable_shared_from_this of both parent and derived

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

like image 585
Artyom Avatar asked Mar 18 '09 06:03

Artyom


People also ask

How does Enable_shared_from_this work?

std::enable_shared_from_this is a standard solution that enables a shared_ptr managed object to acquire a shared_ptr to itself on demand. A class T that publicly inherits an std::enable_shared_from_this<T> encapsulates a std::weak_ptr<T> to itself that can be converted to a std::shared_ptr<T> when needed.

What is Shared_from_this?

shared_from_this. returns a shared_ptr which shares ownership of *this. (public member function)


2 Answers

The OP solution can be made more convenient by defining the following on the base class.

protected:     template <typename Derived>     std::shared_ptr<Derived> shared_from_base()     {         return std::static_pointer_cast<Derived>(shared_from_this());     } 

This can be made more convenient by placing it in a base class (for reuse).

#include <memory>  template <class Base> class enable_shared_from_base   : public std::enable_shared_from_this<Base> { protected:     template <class Derived>     std::shared_ptr<Derived> shared_from_base()     {         return std::static_pointer_cast<Derived>(shared_from_this());     } }; 

and then deriving from it as follows.

class foo : public enable_shared_from_base<foo> {     void foo_do_it()     {         std::cout << "foo::do_it\n";     } public:     virtual std::function<void()> get_callback()     {         return boost::bind(&foo::foo_do_it, shared_from_base<foo>());     } };  class bar1 : public foo {     void bar1_do_it()     {         std::cout << "bar1::do_it\n";     } public:     virtual std::function<void()> get_callback() override     {         return boost::bind(&bar1::bar1_do_it, shared_from_base<bar1>());     } }; 
like image 200
evoskuil Avatar answered Sep 27 '22 23:09

evoskuil


Sorry, but there isn't.

The problem is that shared_ptr<foo> and shared_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 a shared_ptr<foo>, the internal weak_ptr<bar1> sees that nothing is pointing to it (because only a shared_ptr<bar1> would increment the counter) and resets itself. When you call bar1::shared_from_this in get_callback, you get the exception because the internal weak_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.

like image 38
Head Geek Avatar answered Sep 27 '22 23:09

Head Geek