c++boostshared-ptrmultiple-inheritanceenable-shared-from-this

bad weak pointer when base and derived class both inherit from boost::enable_shared_from_this


I have a base class which derives from boost::enable_shared_from_this, and then another class which derives from both the base class and boost::enable_shared_from_this:

#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>

using namespace boost;

class A : public enable_shared_from_this<A> { };

class B : public A , public enable_shared_from_this<B> {
public:
    using enable_shared_from_this<B>::shared_from_this;
};

int main() {
shared_ptr<B> b = shared_ptr<B>(new B());
shared_ptr<B> b_ = b->shared_from_this();

return 0;
}

This compiles but at runtime it gives

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_weak_ptr> >'
  what():  tr1::bad_weak_ptr
Aborted

What is causing this, and is there some way around it?

EDIT:

What if I need something like this:

class A : public enable_shared_from_this<A> { };
class B : public enable_shared_from_this<B> { };    

class C : public A, public B, public enable_shared_from_this<C> {
public:
    using enable_shared_from_this<C>::shared_from_this;
};

such that A and B both need shared_from_this on their own (and one can't inherit it from the other), and C needs A, B, and shared_from_this?


Solution

  • Here's how I would solve your problem:

    #include <boost/enable_shared_from_this.hpp>
    #include <boost/shared_ptr.hpp>
    
    using namespace boost;
    
    class virt_enable_shared_from_this :
       public enable_shared_from_this<virt_enable_shared_from_this>
    {
     public:
       virtual ~virt_enable_shared_from_this() {}
    };
    
    template <class T>
    class my_enable_shared_from_this : virtual public virt_enable_shared_from_this
    {
     public:
       shared_ptr<T> shared_from_this() {
          return dynamic_pointer_cast<T>(virt_enable_shared_from_this::shared_from_this());
       }
    };
    
    class A : public my_enable_shared_from_this<A> { };
    
    class B : public my_enable_shared_from_this<B> { };
    
    class C : public A, public B, public my_enable_shared_from_this<C> {
     public:
       using my_enable_shared_from_this<C>::shared_from_this;
    };
    
    int main() {
       shared_ptr<C> c = shared_ptr<C>(new C());
       shared_ptr<C> c_ = c->shared_from_this();
    
       return 0;
    }
    

    This is painful and at least a bit ugly. But it works reasonably well, after a fashion. I think Fraser's idea of re-thinking your design is likely the better option.