我有简单的基础和派生类,我想要两个shared_from_this()
.
这个简单的方案:
class foo : public enable_shared_from_this{ void foo_do_it() { cout<<"foo::do_it\n"; } public: virtual function get_callback() { return boost::bind(&foo::foo_do_it,shared_from_this()); } virtual ~foo() {}; }; class bar1 : public foo , public enable_shared_from_this { using enable_shared_from_this ::shared_from_this; void bar1_do_it() { cout<<"foo::do_it\n"; } public: virtual function get_callback() { return boost::bind(&bar1::bar1_do_it,shared_from_this()); } };
导致tr1::bad_weak_ptr
以下代码中的异常:
shared_ptrptr(shared_ptr (new bar1)); function f=ptr->get_callback(); f();
所以在"谷歌搜索"之后我找到了以下解决方案:
class bar2 : public foo { void bar2_do_it() { cout<<"foo::do_it\n"; } shared_ptrshared_from_this() { return boost::static_pointer_cast (foo::shared_from_this()); } public: virtual function get_callback() { return boost::bind(&bar2::bar2_do_it,shared_from_this()); } };
现在它有效.
enable_shared_from_this
父母和孩子都有更好,更方便,更正确的方法吗?
谢谢
通过在基类上定义以下内容,可以使OP解决方案更加方便.
protected: templatestd::shared_ptr shared_from_base() { return std::static_pointer_cast (shared_from_this()); }
对不起,但没有.
问题是,shared_ptr
并且shared_ptr
是不同的类型.我不明白幕后发生的一切,但我认为当构造函数返回并被分配给a时shared_ptr
,内部会weak_ptr
看到没有任何东西指向它(因为只有a shared_ptr
会增加计数器)并重置自身.当你打电话bar1::shared_from_this
时get_callback
,你会得到异常,因为内部weak_ptr
没有指向任何东西.
从本质上讲,enable_shared_from_this
似乎只能从层次结构中的单个类透明地工作.如果您尝试手动实现它,问题应该变得明显.
如果你想要实现一个shared_from_this()
函数,那么@evoskuil的类似解决方案可以减少派生类中的样板,从而在类的使用点产生以下代码:
auto shared_from_this() { return shared_from(this); }
这使用了类之外的"shim"函数.通过这样做,它还提供了一种干净的方式来执行此类的接口无法修改但是派生自enable_shared_from_this
- 例如
auto shared_that = shared_from(that);
注意:auto
此处使用for返回类型取决于编译器的使用期限.
可以放在库头中的Shim函数:
templateinline std::shared_ptr shared_from_base(std::enable_shared_from_this * base) { return base->shared_from_this(); } template inline std::shared_ptr shared_from_base(std::enable_shared_from_this const* base) { return base->shared_from_this(); } template inline std::shared_ptr shared_from(That* that) { return std::static_pointer_cast (shared_from_base(that)); }
上面的代码依赖于传递给它的类型在其祖先的某个点shared_from(...)
继承的事实std::enable_shared_from_this
.
调用shared_from_base
将确定最终的类型.由于我们知道That
继承自Base
,因此可以进行静态向下转换.
可能存在一些具有类型转换运算符的类的病态极端情况..但是这不太可能发生在不打算破坏它的代码中.
例:
struct base : public std::enable_shared_from_this{}; struct derived : public base { auto shared_from_this() { return shared_from(this); } // Can also provide a version for const: auto shared_from_this() const { return shared_from(this); } // Note that it is also possible to use shared_from(...) from // outside the class, e.g. // auto sp = shared_from(that); }; template struct derived_x : public derived { auto shared_from_this() { return shared_from(this); } };
编译测试:
int main() { auto pbase = std::make_shared(); auto pderived = std::make_shared (); auto pderived_x = std::make_shared >(); auto const& const_pderived = *pderived; const_pderived.shared_from_this(); std::shared_ptr test1 = pbase->shared_from_this(); std::shared_ptr test2 = pderived->shared_from_this(); std::shared_ptr > test3 = pderived_x->shared_from_this(); return 0; }
https://onlinegdb.com/SJWM5CYIG
我发布的先前解决方案,保持使评论仍然有意义 - 这将函数放在基类中,这有一些问题 - 特别是"普通"类和模板类所需的实现之间的不一致.
另外,对于新的类层次结构,需要重复基类中的实现,这不是所有DRY.此外,基类函数通过从不同对象提供基类指针而遭受滥用的可能性.上面的新方案完全避免了这种情况,并且运行时断言(...)检查结束.
旧实施:
#include#include class base : public std::enable_shared_from_this { protected: template std::shared_ptr shared_from(T* derived) { assert(this == derived); return std::static_pointer_cast (shared_from_this()); } }; class derived : public base { public: auto shared_from_this() { return shared_from(this); } }; template class derived_x : public derived { public: auto shared_from_this() { return this->template shared_from(this); } }; int main() { auto pbase = std::make_shared (); auto pderived = std::make_shared (); auto pderived_x = std::make_shared >(); std::shared_ptr test1 = pbase->shared_from_this(); std::shared_ptr test2 = pderived->shared_from_this(); std::shared_ptr > test3 = pderived_x->shared_from_this(); return 0; }