Double inheritance of enable_shared_from_this

10,119

Solution 1

Yes, as per bad weak pointer when base and derived class both inherit from boost::enable_shared_from_this the solution is to use virtual inheritance. Here's an implementation for the C++11 standard shared_ptr (not Boost):

#include <memory>

struct virtual_enable_shared_from_this_base:
   std::enable_shared_from_this<virtual_enable_shared_from_this_base> {
   virtual ~virtual_enable_shared_from_this_base() {}
};
template<typename T>
struct virtual_enable_shared_from_this:
virtual virtual_enable_shared_from_this_base {
   std::shared_ptr<T> shared_from_this() {
      return std::dynamic_pointer_cast<T>(
         virtual_enable_shared_from_this_base::shared_from_this());
   }
};

struct A: virtual_enable_shared_from_this<A> {};
struct B: virtual_enable_shared_from_this<B> {};
struct Z: A, B { };
int main() {
   std::shared_ptr<Z> z = std::make_shared<Z>();
   std::shared_ptr<B> b = z->B::shared_from_this();
}

This isn't part of the default implementation, probably because of the overhead of virtual inheritance.

Solution 2

Yep, your class will be derived from two distinct classes enable_shared_from_this<A> and enable_shared_from_this<B>, and have two different weak ref's

Trick from that answer allows to have one base class, because of virtual inheritance

Share:
10,119
Offirmo
Author by

Offirmo

~12 years of experience in web development in javascript / html / css, big enterprise apps in C++ and embedded network devices in C. Mostly interested in web app development, javascript, Python, C++... SOreadytohelp !

Updated on June 15, 2022

Comments

  • Offirmo
    Offirmo almost 2 years

    I have an object (Z) which derives from two other objects (A and B).

    A and B both derive from enable_shared_from_this<>, respectively enable_shared_from_this<A> and enable_shared_from_this<B>.

    Of course I call shared_from_this() on Z. And of course the compiler reports this as ambiguous.

    My questions are :

    • is it safe to inherit twice from enable_shared_from_this<> or will it create two separated reference counts (bad !)
    • If not safe, how do I solve this ?

    Note : I've found this other question bad weak pointer when base and derived class both inherit from boost::enable_shared_from_this but it doesn't really answer. Should I use the virtual trick too ?

  • Offirmo
    Offirmo about 11 years
    Why isn't this trick integrated in enable_shared_from_this by default ?
  • kassak
    kassak about 11 years
    @LucDanton It can not deal, because both instatiations of enable shared from this are distinct classes. That is why even vrtually inherited they are distinct. The only way is to have one virtual class, which inherits it with any type argument, and then use that virtual class as base. The only problem can be, in make_shared but I'm not sure
  • Offirmo
    Offirmo about 11 years
    @LucDanton thinking about it, using the "virtual" trick force the derived object to have a virtual table, thus making it bigger. Since C++ philosophy is "you only pay for what you ask", the virtual trick should not be used by default.
  • ecatmur
    ecatmur about 11 years
    @kassak static_pointer_cast won't work; this is virtual inheritance so a dynamic cast is required.
  • kassak
    kassak about 11 years
    but that is simple downcasting from virtual_enable_shared_from_this_base to T, derived from it. Compiler complains?
  • ecatmur
    ecatmur about 11 years
    @kassak yes: cannot convert from base 'virtual_enable_shared_from_this_base' to derived type 'B' via virtual base 'virtual_enable_shared_from_this_base'
  • Luc Danton
    Luc Danton about 11 years
    It may not be the best to mention std::enable_shared_from_this. From what I can tell of the requirements, not using virtual inheritance is still supposed to work (which might be a defect).
  • Luc Danton
    Luc Danton about 11 years
    I made the mistake of thinking that this question was specifically about C++11 and std::enable_shared_from_this, apologies.
  • curiousguy
    curiousguy over 4 years
    Virtual inheritance, like virtual functions, is much less efficient; it generates larger classes, larger vtables, and unreliable code in corner cases. It's very easy to get UB when using virtual bases during construction (arguably not a problem here as that base obviously can't be used during construction).
  • arsdever
    arsdever about 4 years
    Why not to simply virtually derive from enable_from_this? Can you explain to me?
  • ecatmur
    ecatmur about 4 years
    @arsdever enable_shared_from_this is a template, so the two virtual base clases would be different and virtual inheritance wouldn't accomplish anything.