提升shared_from_this和多重继承

时间:2013-02-18 14:59:15

标签: c++ shared-ptr multiple-inheritance

使用boost shared_from_this和多重继承时,我目前遇到了一些麻烦。

该方案可描述如下:

  1. A实现了一些功能,应该继承自shared_from_this

  2. B实现了另一项功能,应该继承自shared_from_this

  3. 班级D继承了ABclass D : public A, public B {}

  4. 的功能
  5. 使用课程B中的某些课程D时,我遇到了异常(weak_ptr

  6. 从班级shared_from_this继承D不是我的选择

  7. 我不确定如何解决这个问题。

    哦,我正在使用Visual C ++ 2010。

3 个答案:

答案 0 :(得分:8)

扩展Potatoswatter的解决方案,如果你可以改变A和B使用与enable_shared_from_this略有不同的东西。代码使用标准库版本,但boost实现应该类似。下面的说明

#include <memory>
template<typename T>
struct enable_shared_from_this_virtual;

class enable_shared_from_this_virtual_base : public std::enable_shared_from_this<enable_shared_from_this_virtual_base>
{
    typedef std::enable_shared_from_this<enable_shared_from_this_virtual_base> base_type;
    template<typename T>
    friend struct enable_shared_from_this_virtual;

    std::shared_ptr<enable_shared_from_this_virtual_base> shared_from_this()
    {
        return base_type::shared_from_this();
    }
    std::shared_ptr<enable_shared_from_this_virtual_base const> shared_from_this() const
    {
       return base_type::shared_from_this();
    }
};

template<typename T>
struct enable_shared_from_this_virtual: virtual enable_shared_from_this_virtual_base
{
    typedef enable_shared_from_this_virtual_base base_type;

public:
    std::shared_ptr<T> shared_from_this()
    {
       std::shared_ptr<T> result(base_type::shared_from_this(), static_cast<T*>(this));
       return result;
    }

    std::shared_ptr<T const> shared_from_this() const
    {
        std::shared_ptr<T const> result(base_type::shared_from_this(), static_cast<T const*>(this));
        return result;
    }
};

因此,意图是struct A将从enable_shared_from_this_virtual<A>公开继承而struct B将从enable_shared_from_this_virtual<B>公开继承。由于它们共享相同的公共虚拟对象,因此层次结构中只有一个std::enable_shared_from_this

当你调用类shared_from_this时,它执行从enable_shared_from_this_virtual<T>*到T *的转换,并使用shared_ptr的别名构造函数,以便新的shared_ptr指向T *并与单个共享所有权共享指针。

使用顶部的朋友是为了防止任何人直接访问虚拟基地的shared_from_this()成员。他们必须经过enable_shared_from_this_virtual<T>提供的那些。

一个例子:

#include <iostream>

struct A : public enable_shared_from_this_virtual<A>
{
    void foo()
    {
        shared_from_this()->baz();
    }

    void baz()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

struct B : public enable_shared_from_this_virtual<B>
{
    void bar()
    {
        shared_from_this()->baz();
    }

    void baz()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

struct D: A, B {};


int main()
{
 std::shared_ptr<D> d(new D);
 d->foo();
 d->bar();
 return 0;
}

答案 1 :(得分:4)

shared_ptr是不可见容器对象或“控制块”的观察者。这个容器总是在堆上,永远不在堆栈上,你无法直接处理它。虽然shared_ptrweak_ptr提供了唯一的观察方法,但仍然有一个拥有该对象的隐藏层。这是隐藏层,填充enable_shared_from_this

不允许来自enable_shared_from_this的多重继承,因为所有enable_shared_from_this个基都需要单独初始化,但控制块无法获取给定类型的所有基础子对象的列表。它所能得到的只是一个模糊的基本错误。

我看到的唯一解决方案是添加virtual基类AB,其继承自enable_shared_from_this。您可以为此目的指定一个特定的类:

struct shared_from_this_virtual_base
    : std::enable_shared_from_this< shared_from_this_virtual_base >
    {};

struct shared_from_this_base : virtual shared_from_this_virtual_base {};

struct A : shared_from_this_base { … };
struct B : shared_from_this_base { … };

但是,还有另一个问题:你不能从virtual基础向下投射,因为AB包含shared_from_this_virtual_base是不明确的。要恢复A*B*,您必须将这些指针添加到shared_from_this_virtual_base中的某种注册表结构中。这可能会通过向shared_from_this_base添加另一个CRTP模式来填充。对于C ++来说,这比通常的步法要多一些,但我没有看到任何概念上的捷径。

编辑:啊,获得向下转发的最简单方法是将void*成员放入shared_from_this_virtual_base,然后将其转发到D*的任何客户端代码具有D的知识。相当可行,如果不是非常优雅。或者boost::any可以提供更安全的替代方案。

答案 2 :(得分:2)

标准对于shared_from_this应该如何实现有点模糊,但所有实现似乎都同意,因为Boost提供了参考实现。

当您创建boost::shared_ptr<D> myD(new D())时,shared_ptr构造函数会检查某些D*是否存在从enable_shared_from_this<X>*X的明确转换(这意味着D 1}}有一个类型为enable_shared_from_this<X>的基类。如果转换有效,则基类中的weak_ptr<X>将设置为引用新创建的shared_ptr

在您的代码中,有两种可能的转化,enable_shared_from_this<A>enable_shared_from_this<B>,这是不明确的,因此没有设置weak_ptr来引用myD。这意味着如果B之后的成员函数调用shared_from_this(),它将获得bad_weak_ptr例外,因为其enable_shared_from_this<B>成员从未设置过。