плохой слабый указатель, когда базовый и производный классы наследуют от boost:: enable shared from this
У меня есть базовый класс, производный от boost:: enable_shared_from_this, а затем еще один класс, производный как от базового класса, так и от 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;
}
Это компилируется, но во время выполнения он дает
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
Что является причиной этого, и есть ли какой-то способ обойти это?
Правка:
Что, если мне нужно что-то вроде этого:
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;
};
Таким образом, что A и B оба нуждаются в shared_from_this самостоятельно (и один не может наследовать его от другого), А C нужны A, B и shared_from_this?
2 ответов:
Вот как бы я решил вашу проблему:
Это болезненно и, по крайней мере, немного некрасиво. Но это работает довольно хорошо, в некотором роде. Я думаю, что идея Фрейзера о переосмыслении вашего дизайна, вероятно, является лучшим вариантом.#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; }
Вы не должны наследовать от
enable_shared_from_thisболее одного раза в данной цепочке наследования.В этом случае можно оставить базовый класс
Aнаследующим отenable_shared_from_this, а производный классBвернуть ashared_ptr<A>и затемstatic_pointer_castэто кshared_ptr<B>.Или, как указал Omnifarious, у вас может быть функция в
B, которая делает это за вас. Хотя, вместо того, чтобы перегружатьshared_from_this(), я бы предпочел явно именованные функции, чтобы минимизировать сюрпризы для клиентов класс:#include <boost/enable_shared_from_this.hpp> #include <boost/shared_ptr.hpp> using boost::shared_ptr; class A : public boost::enable_shared_from_this<A> { }; class B : public A { public: using enable_shared_from_this<A>::shared_from_this; shared_ptr<B> shared_B_from_this() { return boost::static_pointer_cast<B>(shared_from_this()); } shared_ptr<B const> shared_B_from_this() const { return boost::static_pointer_cast<B const>(shared_from_this()); } }; int main() { shared_ptr<B> b = shared_ptr<B>(new B); shared_ptr<B> b1 = boost::static_pointer_cast<B>(b->shared_from_this()); shared_ptr<B> b2 = b->shared_B_from_this(); return 0; }
Comments