【问题标题】:Why does enable_shared_from_this lack direct access to the embedded weak_ptr?为什么 enable_shared_from_this 无法直接访问嵌入的weak_ptr?
【发布时间】:2013-04-10 14:38:47
【问题描述】:

我想在多线程应用程序中使用带有自动连接管理的升压信号2。我的类继承自enable_shared_from_this<>,我想从另一个成员方法中连接一个成员方法。连接可能会经常重建,因此我的代码应该尽可能快(尽管提升了信号 2 性能本身):

typedef boost::signals2::signal<void ()> signal_type;

struct Cat : public enable_shared_from_this<Cat>
{
  void meow ();

  void connect (signal_type& s)
  {
    // can't write this
    s.connect (signal_type::slot_type (&Cat::meow, this, _1).track (weak_from_this ()));

    // ok, but slow?! two temporary smart pointers
    weak_ptr<Cat> const myself (shared_from_this ());
    s.connect (signal_type::slot_type (&Cat::meow, this, _1).track (myself));
  }

  // i am missing something like this in the base class
  // protected:
  //   weak_ptr<Cat> const& weak_from_this ();
};

我知道我的设计目标可能会相互冲突(自动连接管理和线程安全以及快速代码),但无论如何:

  1. 为什么enable_shared_from_this&lt;&gt; 无法直接访问嵌入式weak_ptr&lt;&gt;?我看不到相反的理由。有没有和我类似的用例?

  2. 有比上述更快的解决方法吗?

编辑:

我知道我可以这样做,但我想避免额外的存储/初始化检查惩罚:

template <typename T>
struct enable_weak_from_this : public enable_shared_from_this<T>
{
protected:
  weak_ptr<T> /* const& */ weak_from_this ()
  {
    if (mWeakFromThis.expired ())
    {
      mWeakFromThis = this->shared_from_this ();
    }

    return mWeakFromThis;
  }

private:
  weak_ptr<T> mWeakFromThis;
};

【问题讨论】:

  • 谁说那是“慢”?什么是“慢”?
  • 我需要两个临时智能指针实例,这将导致至少 4 次多余的互锁操作,只是为了构造一个已经存在的 weak_ptr。
  • 首先,它“已经存在”;看我的回答。其次,这不会使它。您是否有一些分析数据表明这是一个问题?
  • 因为enable_shared_from_this 接口不是必需 来使用weak_ptr,但实际上可以 - 为什么不直接创建自己的enable_weak_from_this?原件小于 80 行,包括版权信息和空格。你想做一些不同于图书馆提供的常见情况的事情,所以你可以自己做。
  • 这将是 C++17 的一部分,请参阅:en.cppreference.com/w/cpp/memory/enable_shared_from_this/…

标签: c++ shared-ptr boost-signals2


【解决方案1】:

您无法访问weak_ptr 的原因是enable_shared_from_this 没有必须使用一个。拥有weak_ptr 只是enable_shared_from_this 的一种可能 实现。它不是唯一的。

由于enable_shared_from_thisshared_ptr 属于同一标准库,因此可以使用比直接存储weak_ptr 更有效的实现。而且委员会不想阻止这种优化。

// 好的,但是慢?!两个临时智能指针

这只是一个临时智能指针。复制省略/移动应该处理除第一个对象之外的任何内容。

【讨论】:

  • 我知道标准并没有定义/限制实际的实现。但是,如果标准提供 shared_from_this() 它也可以提供 weak_from_this() 而不限制实际实现。内部使用weak_ptr 的实现可以提供weak_from_this() 的快速(er) 实现。
  • 复制省略真的在这里有效吗?我们这里有weak_ptr => shared_ptr => weak_ptr 而不是weak_ptr => weak_ptr => weak_ptr。
  • @user2266052:你说有“两个临时智能指针”。 WP->SP->WP 只使用 one 临时的 SP(使用 WP->WP,你仍然需要复制它)。所以我假设第二个是weak_ptr的构造函数的参数什么的。
  • @user2266052: "它也可以提供weak_from_this()" 你说得对;它可能。但是……他们为什么要这样做?这个过程的时间对于任何人来说都不太可能成为性能问题。
  • 我认为weak_ptr 和shared_ptr 都是智能指针。我们这里有两个额外的智能指针(一个 shared_ptr 实例和一个 weak_ptr 实例),优化无法消除它们。我逐步完成了(发布)构建,您可以清楚地看到四个(多余的)互锁操作(msvc2010 的 3 个 inc/dec 和 1 个交换操作,带有来自 boost 的智能指针)。在简单的单线程设置中,额外的成本当然可以忽略不计。其他代码(如我用例中的信号管理内容)显然主导了整体性能。
【解决方案2】:

这可能是因为没有 shared_ptr 引用 Cat 实例。 weak_ptr 要求至少有一个活动的shared_ptr

尝试将shared_ptr 作为成员变量并首先在connect 方法中分配给它:

typedef boost::signals2::signal<void ()> signal_type;

struct Cat : public enable_shared_from_this<Cat>
{
  void meow ();
  boost::shared_ptr<Cat> test;

  void connect (signal_type& s)
  {
    test = shared_from_this();
    s.connect (signal_type::slot_type (&Cat::meow, this, _1).track (weak_from_this ()));
  }
};

但基本上,如果没有shared_ptr,就不可能有weak_ptr。 如果所有shared_ptr 都消失了,而weak_ptr 仍在使用中,那么weak_ptr 可能指向一个不存在的对象。

注意:我的测试不应该在生产代码中使用,因为它会导致对象永远不会被释放。

【讨论】:

  • 你误解了我的问题。存在一个管理 cat 对象生命周期的 shared_ptr 实例。我没有问题让我的代码工作(它确实)但让它更快。
猜你喜欢
  • 2011-10-13
  • 1970-01-01
  • 2011-05-02
  • 1970-01-01
  • 1970-01-01
  • 2020-03-17
  • 2011-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多