我有一个简单的基类和派生类,我希望它们都有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());
}
};
在以下代码中导致异常tr1::bad_weak_ptr
:
shared_ptr<foo> ptr(shared_ptr<foo>(new bar1));
function<void()> f=ptr->get_callback();
f();
所以在“google”之后,我找到了以下解决方案:
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());
}
};
现在成功了
有没有更好的,更方便,更正确的方法来enable_shared_from_this
的父母和孩子?
谢谢
6条答案
按热度按时间9vw9lbht1#
OP解决方案可以通过在基类上定义以下内容变得更加方便。
这可以通过将其放置在基类中(以供重用)来变得更方便。
然后如下导出。
63lcw9qa2#
抱歉,没有。
问题是
shared_ptr<foo>
和shared_ptr<bar1>
是不同的类型。我并不理解这背后发生的一切,但我 * 认为 * 当构造函数返回并被赋值给shared_ptr<foo>
时,内部的weak_ptr<bar1>
会发现没有任何东西指向它(因为只有shared_ptr<bar1>
会递增计数器)并重置自己。当您在get_callback
中调用bar1::shared_from_this
时,您会得到异常,因为内部weak_ptr
没有指向任何东西。从本质上讲,
enable_shared_from_this
似乎只能从层次结构中的单个类透明地工作。如果您尝试手动实现它,问题应该会变得很明显。zed5wv103#
如果你想实现一个
shared_from_this()
函数,一个类似于@evoskuil的解决方案可以减少派生类中的样板文件,在类中的使用点产生以下代码:这在类外部使用了“shim”函数。通过这种方式,它也为那些接口不能修改但从
enable_shared_from_this
派生的类提供了一种干净的方法。注意:在这里使用
auto
作为返回类型将取决于编译器的年龄。可以放置在库头中的Shim函数:
上面的代码依赖于这样一个事实,即传递给
shared_from(...)
的类型在其祖先的某个点上继承自std::enable_shared_from_this<Base>
。调用
shared_from_base
将找出最终的类型。由于我们知道That
继承自Base
,因此可以进行静态向下转换。可能有一些病态的极端情况,类具有类型转换操作符。但这不太可能发生在没有设计来破坏它的代码中。
示例:
编译测试:
https://onlinegdb.com/SJWM5CYIG
我发布的之前的解决方案,保持注解仍然有意义-这将函数放在基类中,这有一些问题-特别是“正常”类和模板类所需的实现之间的不一致性。
此外,对于新的类层次结构,需要重复基类中的实现,这并不完全是DRY。此外,基类函数可能会因提供来自不同对象的基类指针而被误用。上面较新的方案完全避免了这一点,并且运行时Assert(...)检查消失了。
旧实现:
5hcedyr04#
非常简单;只在基类中继承
public shared_from_this
。在派生类中实现强制转换为适当类型的访问器;kqlmhetl5#
dojqjjoe6#
使用c++23推导出这一点,事情变得容易得多。https://godbolt.org/z/j499WK58Y
这是以前的答案:
我不喜欢虚拟函数。虚函数只是用于类型擦除,但我们并不总是需要类型擦除。因此,提供一种类型擦除机制就足够了。下面是一个不使用虚函数的例子: