I am currently having some troubles when using boost enable_shared_from_this
and multiple inheritance.
The scenario can be described as follows:
Class A
implements some functionality and should inherit from enable_shared_from_this
Class B
implements another functionality and should inherit from enable_shared_from_this
Class D
inherits functionalities from A
and B
(class D : public A, public B {}
)
When using some class B
functionality from class D
I got an exception (bad_weak_ptr
)
To inherit enable_shared_from_this
from class D
is not an option for me
I am not sure about how to solve this.
Oh, I am using Visual C++ 2010.
Expanding on Potatoswatter's solution, if you can change A and B to use a something slightly different than enable_shared_from_this. The code uses the standard library versions, but the boost implementation should be similar. Explanation below
#include <memory>
template<typename T>
struct enable_shared_from_this_virtual;
class enable_shared_from_this_virtual_base : public std::enable_shared_from_this<enable_shared_from_this_virtual_base>
{
typedef std::enable_shared_from_this<enable_shared_from_this_virtual_base> base_type;
template<typename T>
friend struct enable_shared_from_this_virtual;
std::shared_ptr<enable_shared_from_this_virtual_base> shared_from_this()
{
return base_type::shared_from_this();
}
std::shared_ptr<enable_shared_from_this_virtual_base const> shared_from_this() const
{
return base_type::shared_from_this();
}
};
template<typename T>
struct enable_shared_from_this_virtual: virtual enable_shared_from_this_virtual_base
{
typedef enable_shared_from_this_virtual_base base_type;
public:
std::shared_ptr<T> shared_from_this()
{
std::shared_ptr<T> result(base_type::shared_from_this(), static_cast<T*>(this));
return result;
}
std::shared_ptr<T const> shared_from_this() const
{
std::shared_ptr<T const> result(base_type::shared_from_this(), static_cast<T const*>(this));
return result;
}
};
So, the intent is that struct A
would inherit publicly from enable_shared_from_this_virtual<A>
and struct B
would inherit publicly from enable_shared_from_this_virtual<B>
. Since they both share the same common virtual object, there is only one std::enable_shared_from_this
in the hierarchy.
When you call either classes shared_from_this
, it performs a cast from enable_shared_from_this_virtual<T>*
to T*, and uses the aliasing constructor of shared_ptr so that the new shared_ptr points to T* and shares ownership with the single shared pointer.
The use of the friend at the top is to prevent anyone from accessing the shared_from_this() members of the virtual base directly. They have to go through the ones provided by enable_shared_from_this_virtual<T>
.
An example:
#include <iostream>
struct A : public enable_shared_from_this_virtual<A>
{
void foo()
{
shared_from_this()->baz();
}
void baz()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
struct B : public enable_shared_from_this_virtual<B>
{
void bar()
{
shared_from_this()->baz();
}
void baz()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
struct D: A, B {};
int main()
{
std::shared_ptr<D> d(new D);
d->foo();
d->bar();
return 0;
}