当前位置:  开发笔记 > 编程语言 > 正文

如何enable_shared_from_this父和派生

如何解决《如何enable_shared_from_this父和派生》经验,为你挑选了3个好方法。

我有简单的基础和派生类,我想要两个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_ptr ptr(shared_ptr(new bar1));
function f=ptr->get_callback();
f();

所以在"谷歌搜索"之后我找到了以下解决方案:

class bar2 : public foo {
    void bar2_do_it()
    {
        cout<<"foo::do_it\n";
    }
    shared_ptr shared_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父母和孩子都有更好,更方便,更正确的方法吗?

谢谢



1> evoskuil..:

通过在基类上定义以下内容,可以使OP解决方案更加方便.

protected:
    template 
    std::shared_ptr shared_from_base()
    {
        return std::static_pointer_cast(shared_from_this());
    }



2> Head Geek..:

对不起,但没有.

问题是,shared_ptr并且shared_ptr是不同的类型.我不明白幕后发生的一切,但我认为当构造函数返回并被分配给a时shared_ptr,内部会weak_ptr看到没有任何东西指向它(因为只有a shared_ptr会增加计数器)并重置自身.当你打电话bar1::shared_from_thisget_callback,你会得到异常,因为内部weak_ptr没有指向任何东西.

从本质上讲,enable_shared_from_this似乎只能从层次结构中的单个类透明地工作.如果您尝试手动实现它,问题应该变得明显.


我尝试手动实现它,实际上并没有那么难.在`My :: SmartPointer `中,检查T是否来自`My :: enableSmartFromThis`.如果是这样,不要在堆上分配引用计数器,而是使用`My :: enableSmartFromThis`的成员.现在`My :: GetSmartFromThis(this)`变得微不足道,它可以将`this`转换为`My :: enableSmartFromThis*`并找到现有的引用计数.当只有Derived派生自`My :: enableSmartFromThis`时,你甚至可以检查你是否试图从Base转换为Derived.

3> Pete..:

如果你想要实现一个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函数:

template 
inline 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;
}

推荐阅读
郑谊099_448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有