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