【问题标题】:boost shared_from_this and multiple inheritance提升 shared_from_this 和多重继承
【发布时间】:2013-02-18 14:59:15
【问题描述】:

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

场景可以描述如下:

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

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

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

  4. 使用 D 类中的某些类 B 功能时出现异常 (bad_weak_ptr)

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

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

哦,我使用的是 Visual C++ 2010。

【问题讨论】:

  • 糟糕,感谢您编辑 leemes。
  • 如何创建持有 D 的共享指针?
  • 嗨,戴夫。我将其创建为: boost::shared_ptr myD(new D())

标签: c++ shared-ptr multiple-inheritance enable-shared-from-this


【解决方案1】:

扩展 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&lt;A&gt; 公开继承,struct B 将公开从enable_shared_from_this_virtual&lt;B&gt; 继承。由于它们都共享相同的公共虚拟对象,因此层次结构中只有一个std::enable_shared_from_this

当您调用任一类 shared_from_this 时,它会执行从 enable_shared_from_this_virtual&lt;T&gt;* 到 T* 的强制转换,并使用 shared_ptr 的别名构造函数,以便新的 shared_ptr 指向 T* 并与单个共享指针共享所有权。

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

一个例子:

#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;
}

【讨论】:

  • 在 enable_shared_from_this_virtual 中的第二个“shared_from_this 函数中,您的意思是要返回一个 shared_ptr
  • 从网络上的许多其他实现中我会推荐这个,因为它足够简单并且不使用dynamic_cast&lt;T&gt;。在使用/开发共享库或 RTTI 不可用时,dynamic_cast&lt;T&gt; 是一个大问题。
【解决方案2】:

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 中,然后在任何客户端代码知道@987654343 的情况下将其转换为D* @。相当可行,即使不是非常优雅。或者boost::any 可以提供更安全的选择。

【讨论】:

  • 谢谢。您如何看待我在 Jonathan Wakely 的回答中的评论?该解决方案正确吗?
  • @user1963961 这取决于D 是否是A 的唯一派生类。如果是,则解决方案有效,但问题一开始就不存在。如果还有其他派生类,那么您需要告诉所有基类在哪里可以找到shared_from_this。所以这意味着基数AB 的CRTP。仅当 AB 已经是混合组件时才可行,这有助于定义仅一个 D 的“底层”实现。
  • 我不喜欢这个答案中的解释 - enable_shared_from_this 只是将 weak_ptr 保存到其他地方的控制块,它不会导致 delete this 或将所有权放入对象中
  • @JonathanWakely 我掩饰了一点。控制块实际上保存在共享对象内,尽管理论上它可能在其他地方。理所当然地考虑这个实现细节,最终结果是enable_shared_from_this&lt;derived&gt; 将自身向下转换为派生类型并删除结果指针。我的解释可能过于具体,无法反映标准规范,但是以这种方式组织概念可以使问题更容易理解,而且我认为我没有丢失任何东西或引入任何错误的困境。
  • 在 Boost 或 GCC 的实现中,控制块不保存在共享对象中。销毁共享对象与enable_shared_from_this 完全正交,不受共享对象是否派生自它的影响。您的解释与我熟悉的 shared_ptr 实现毫无相似之处。
【解决方案3】:

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

当您创建 boost::shared_ptr&lt;D&gt; myD(new D()) 时,shared_ptr 构造函数检查是否存在从 D*enable_shared_from_this&lt;X&gt;* 的明确转换,用于某些 X(这意味着 D 具有类型为 enable_shared_from_this&lt;X&gt; 的基类)。如果转换成功,那么基类中的weak_ptr&lt;X&gt; 将被设置为引用新创建的shared_ptr

在您的代码中,有两种可能的转换为enable_shared_from_this&lt;A&gt;enable_shared_from_this&lt;B&gt;,这是不明确的,因此没有设置weak_ptr 来引用myD。这意味着如果B 的成员函数稍后调用shared_from_this(),它将得到bad_weak_ptr 异常,因为它的enable_shared_from_this&lt;B&gt; 成员从未设置。

【讨论】:

猜你喜欢
  • 2011-04-07
  • 2020-01-02
  • 1970-01-01
  • 1970-01-01
  • 2017-03-23
  • 2011-06-10
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
相关资源
最近更新 更多