【问题标题】:bad weak pointer when base and derived class both inherit from boost::enable_shared_from_this当基类和派生类都继承自 boost::enable_shared_from_this 时出现错误的弱指针
【发布时间】:2012-10-08 23:25:15
【问题描述】:

我有一个派生自 boost::enable_shared_from_this 的基类,然后是另一个派生自基类和 boost::enable_shared_from_this 的类:

#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>

using namespace boost;

class A : public enable_shared_from_this<A> { };

class B : public A , public enable_shared_from_this<B> {
public:
    using enable_shared_from_this<B>::shared_from_this;
};

int main() {
shared_ptr<B> b = shared_ptr<B>(new B());
shared_ptr<B> b_ = b->shared_from_this();

return 0;
}

这会编译,但在运行时会给出

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_weak_ptr> >'
  what():  tr1::bad_weak_ptr
Aborted

是什么原因造成的,有什么办法可以解决吗?

编辑:

如果我需要这样的东西怎么办:

class A : public enable_shared_from_this<A> { };
class B : public enable_shared_from_this<B> { };    

class C : public A, public B, public enable_shared_from_this<C> {
public:
    using enable_shared_from_this<C>::shared_from_this;
};

这样 A 和 B 都需要自己的 shared_from_this (并且不能从另一个继承它),而 C 需要 A、B 和 shared_from_this?

【问题讨论】:

  • 我知道 b_ 将与 b 相同,在这种情况下我可以只使用 b。但这只是一个演示;我实际需要使用 shared_from_this 的其他情况会导致相同的错误。
  • 在这种情况下,我的解决方案将涉及虚拟继承。我怀疑 boost 可能已经有一个类,可能是enable_shared_from_this 的非模板版本。但如果没有,我会创建我自己的,并在我需要该功能的任何地方从它虚拟继承。当然,您必须使用dynamic_pointer_cast 而不是static_pointer_cast。但它会工作。
  • 是的 - 我看不到一个明显干净的方法来完成这项工作。它接近于钻石继承,可能表明重新考虑设计是有序的。

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


【解决方案1】:

您不应在给定的继承链中多次从 enable_shared_from_this 继承。

在这种情况下,您可以让基类A 继承自enable_shared_from_this,并让派生类B 返回一个shared_ptr&lt;A&gt;,然后将static_pointer_cast 返回到shared_ptr&lt;B&gt;

或者正如 Omnifarious 指出的那样,您可以在 B 中有一个函数为您执行此操作。虽然,比起重载shared_from_this(),我更倾向于使用显式命名的函数来最大程度地减少类客户的意外:

#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>

using boost::shared_ptr;

class A : public boost::enable_shared_from_this<A> { };

class B : public A {
public:
    using enable_shared_from_this<A>::shared_from_this;
    shared_ptr<B> shared_B_from_this() {
        return boost::static_pointer_cast<B>(shared_from_this());
    }
    shared_ptr<B const> shared_B_from_this() const {
        return boost::static_pointer_cast<B const>(shared_from_this());
    }
};

int main() {
    shared_ptr<B> b = shared_ptr<B>(new B);
    shared_ptr<B> b1 = boost::static_pointer_cast<B>(b->shared_from_this());
    shared_ptr<B> b2 = b->shared_B_from_this();
    return 0;
}

【讨论】:

  • 或者更好的是,在派生类中重载 shared_from_this 来为你做演员。
  • 我担心答案会是这样。这是一个更接近我实际情况的情况:class A : public enable_shared_from_this&lt;A&gt; { }; class B : public enable_shared_from_this&lt;B&gt; { }; class C : public A, public B, public enable_shared_from_this&lt;C&gt; { public: using enable_shared_from_this&lt;C&gt;::shared_from_this; }; 所以你可以看到 A 不能通过从 B 继承来获得 shared_from_this (反之亦然)。那么如何在 A、B 和 C 中都使用 use shared_from_this 呢?
  • gah 评论系统删除了新行,这使得它几乎无法阅读。我也会编辑我原来的问题。
【解决方案2】:

以下是我将如何解决您的问题:

#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>

using namespace boost;

class virt_enable_shared_from_this :
   public enable_shared_from_this<virt_enable_shared_from_this>
{
 public:
   virtual ~virt_enable_shared_from_this() {}
};

template <class T>
class my_enable_shared_from_this : virtual public virt_enable_shared_from_this
{
 public:
   shared_ptr<T> shared_from_this() {
      return dynamic_pointer_cast<T>(virt_enable_shared_from_this::shared_from_this());
   }
};

class A : public my_enable_shared_from_this<A> { };

class B : public my_enable_shared_from_this<B> { };

class C : public A, public B, public my_enable_shared_from_this<C> {
 public:
   using my_enable_shared_from_this<C>::shared_from_this;
};

int main() {
   shared_ptr<C> c = shared_ptr<C>(new C());
   shared_ptr<C> c_ = c->shared_from_this();

   return 0;
}

这很痛苦,至少有点难看。但经过一段时间后,它的效果相当不错。我认为Fraser 重新思考您的设计的想法可能是更好的选择。

【讨论】:

  • 如果没有从enable_shared_from_this 继承virtually,我不明白virt_enable_shared_from_this 的用途。
  • @MatthieuM.: enable_shared_from_this 是一个模板。因此,实际上从模板继承的每个人都无济于事,因为每个模板实例都是不同的。 virt_enable_shared_from_this 是为每个人提供一个通用的基类以虚拟继承。
  • 我认为你可以将dynamic_pointer_cast 替换为static_pointer_cast 它在这里很安全......而且速度更快
  • @kassak:也许吧。我不想冒险。虚拟基类可以以有趣的方式在类布局中浮动。
猜你喜欢
  • 2016-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-16
  • 2011-02-11
  • 1970-01-01
  • 1970-01-01
  • 2016-12-02
相关资源
最近更新 更多