【问题标题】:Double inheritance of enable_shared_from_thisenable_shared_from_this 的双重继承
【发布时间】:2013-03-21 14:03:34
【问题描述】:

我有一个从其他两个对象(A 和 B)派生的对象 (Z)。

A 和 B 都派生自 enable_shared_from_this<>,分别是 enable_shared_from_this<A>enable_shared_from_this<B>

当然,我在 Z 上调用 shared_from_this()。当然编译器会将此报告为模棱两可。

我的问题是:

  • enable_shared_from_this<> 继承两次是安全的还是会创建两个单独的引用计数(不好!)
  • 如果不安全,我该如何解决?

注意: 我发现了另一个问题bad weak pointer when base and derived class both inherit from boost::enable_shared_from_this,但它并没有真正回答。我也应该使用virtual 技巧吗?

【问题讨论】:

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


【解决方案1】:

是的,根据bad weak pointer when base and derived class both inherit from boost::enable_shared_from_this,解决方案是使用虚拟继承。这是 C++11 标准 shared_ptr(不是 Boost)的实现:

#include <memory>

struct virtual_enable_shared_from_this_base:
   std::enable_shared_from_this<virtual_enable_shared_from_this_base> {
   virtual ~virtual_enable_shared_from_this_base() {}
};
template<typename T>
struct virtual_enable_shared_from_this:
virtual virtual_enable_shared_from_this_base {
   std::shared_ptr<T> shared_from_this() {
      return std::dynamic_pointer_cast<T>(
         virtual_enable_shared_from_this_base::shared_from_this());
   }
};

struct A: virtual_enable_shared_from_this<A> {};
struct B: virtual_enable_shared_from_this<B> {};
struct Z: A, B { };
int main() {
   std::shared_ptr<Z> z = std::make_shared<Z>();
   std::shared_ptr<B> b = z->B::shared_from_this();
}

这不是默认实现的一部分,可能是因为虚拟继承的开销。

【讨论】:

  • @kassak static_pointer_cast 不起作用;这是虚拟继承,因此需要动态转换。
  • 但这是从virtual_enable_shared_from_this_baseT 的简单向下转换,源自它。编译器抱怨?
  • @kassak 是:cannot convert from base 'virtual_enable_shared_from_this_base' to derived type 'B' via virtual base 'virtual_enable_shared_from_this_base'
  • 提及std::enable_shared_from_this 可能不是最好的选择。根据我对需求的了解,不使用虚拟继承仍然应该有效(这可能是一个缺陷)。
  • @arsdever enable_shared_from_this 是一个模板,所以两个虚拟基类会不同,虚拟继承不会完成任何事情。
【解决方案2】:

是的,你的类将派生自两个不同的类 enable_shared_from_this&lt;A&gt;enable_shared_from_this&lt;B&gt;,并且有两个不同的弱引用

该答案的技巧允许拥有一个基类,因为虚拟继承

【讨论】:

  • 为什么enable_shared_from_this默认不集成这个技巧?
  • @LucDanton 它不能处理,因为从这里共享的启用的两个实例都是不同的类。这就是为什么即使实际上继承了它们也是不同的。唯一的方法是拥有一个虚拟类,它使用任何类型参数继承它,然后使用该虚拟类作为基础。唯一的问题可能是,make_shared,但我不确定
  • @LucDanton 考虑了一下,使用“虚拟”技巧强制派生对象具有虚拟表,从而使其更大。由于 C++ 的理念是“你只为你所问的东西付费”,因此默认情况下不应该使用虚拟技巧。
  • 我误以为这个问题专门针对 C++11 和 std::enable_shared_from_this,抱歉。
【解决方案3】:

使用 shared_ptr 别名构造函数,可以得出 ecatmur 答案的变体:

#include <memory>

struct virtual_enable_shared_from_this_base:
   std::enable_shared_from_this<virtual_enable_shared_from_this_base> {
   virtual ~virtual_enable_shared_from_this_base() {}
};
template<typename T>
struct virtual_enable_shared_from_this:
virtual virtual_enable_shared_from_this_base {
   std::shared_ptr<T> shared_from_this() {
      return std::shared_ptr<T>(
         virtual_enable_shared_from_this_base::shared_from_this(),
         static_cast<T*>(this));
   }
   std::shared_ptr<const T> shared_from_this() const {
      return std::shared_ptr<const T>(
         virtual_enable_shared_from_this_base::shared_from_this(),
         static_cast<const T*>(this));
   }
};

struct A: virtual_enable_shared_from_this<A> {};
struct B: virtual_enable_shared_from_this<B> {};
struct Z: A, B { };
int main() {
   std::shared_ptr<Z> z = std::make_shared<Z>();
   std::shared_ptr<B> b = z->B::shared_from_this();
}

我希望这个版本在许多情况下会更快,因为它避免了代价高昂的动态转换。但是,像往常一样,只有 becnhmarks 有最终决定权。另外,我添加了const 变体。

【讨论】:

    猜你喜欢
    • 2011-05-28
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    • 2018-04-27
    • 2020-11-11
    • 2022-01-26
    • 2012-08-06
    相关资源
    最近更新 更多