13

我目前在使用 boostenable_shared_from_this和多重继承时遇到了一些麻烦。

该场景可以描述如下:

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

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

  3. 类从和( )D继承功能ABclass D : public A, public B {}

  4. 当使用类中的某些类B功能时,D我遇到了异常(bad_weak_ptr

  5. enable_shared_from_this从类继承D不是我的选择

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

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

4

3 回答 3

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

当您调用任一 classesshared_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;
}
于 2013-02-18T17:25:16.190 回答
4

Ashared_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*orB*您必须将这些指针添加到shared_from_this_virtual_base. 这可能会通过将另一个 CRTP 模式添加到shared_from_this_base. 对于 C++ 来说,这比平时多一些步法,但我没有看到任何概念上的捷径。

编辑:啊,获得沮丧的最简单方法是放入一个void*成员,shared_from_this_virtual_base然后将其转换D*为任何客户端代码所知道的D. 相当可行,即使不是非常优雅。或者boost::any可以提供更安全的替代方案。

于 2013-02-18T16:00:50.070 回答
2

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

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

在您的代码中,有两种可能的转换, toenable_shared_from_this<A>enable_shared_from_this<B>,这是不明确的,因此 noweak_ptr设置为引用myD. B这意味着如果稍后调用的成员函数shared_from_this()将得到一个bad_weak_ptr异常,因为它的enable_shared_from_this<B>成员从未设置过。

于 2013-02-18T15:30:26.057 回答