问题
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 ?
回答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.
回答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
回答3:
Using the shared_ptr
aliasing constructor, a variation of ecatmur's answer can be derived:
#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::shared_ptr<T>(
virtual_enable_shared_from_this_base::shared_from_this(),
static_cast<T*>(this));
}
std::shared_ptr<const T> shared_from_this() const {
return std::shared_ptr<const T>(
virtual_enable_shared_from_this_base::shared_from_this(),
static_cast<const T*>(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();
}
I expect this version to be faster in many circumstances, since it avoids a costly dynamic cast. However, as usual, only becnhmarks have the final word. Also, I have added the const
variation.
来源:https://stackoverflow.com/questions/15549722/double-inheritance-of-enable-shared-from-this