【问题标题】:Is it useful to pass std::weak_ptr to functions?将 std::weak_ptr 传递给函数有用吗?
【发布时间】:2019-05-05 01:30:33
【问题描述】:

我正在阅读 Herb Sutter 撰写的 this article 关于将智能指针传递给函数的内容。他没有提到std::weak_ptr,老实说,我找不到传递这种智能指针有用的好场景。

函数是否拥有所有权?通过std::shared_ptr。该函数是否只需要对底层对象进行操作?传递原始指针或引用。

那么将std::weak_ptr 传递给函数100% 没用吗?

【问题讨论】:

  • 到函数,是的,也许,到方法,那么这很有趣。
  • 这真的取决于用例。 std::weak_ptr 告诉您您不拥有该对象,并且在您尝试获取共享所有权之前它可能已经消失。如果这就是你想要的,那么这就是你应该使用的。

标签: c++ c++11 smart-pointers


【解决方案1】:

那么将std::weak_ptr 传递给函数100% 没用吗?

没有。

考虑这个玩具示例。

struct PointerObserver
{
    std::weak_ptr<int> held_pointer;

    void observe( std::weak_ptr<int> p )
    {
        held_pointer = std::move(p);
    }

    void report() const
    {
        if ( auto sp = held_pointer.lock() )
        {
            std::cout << "Pointer points to " << *sp << "\n";
        }
        else
        {
            std::cout << "Pointer has expired.\n";
        }
    }
};

在此示例中,成员函数 observe 保持传递给它的 weak_ptr。这通常称为“接收器参数”。

weak_ptr 参数表明此传递的指针不拥有,但保留在以后拥有的能力,安全地检测指针是否已过期。

作为一个不同的例子,一个不保持状态供以后使用的函数也可以在关联数据可能过期的多线程上下文中有用地接收weak_ptr参数> 当函数工作时。

【讨论】:

【解决方案2】:

如果您的客户有一个weak_ptr,并且您的逻辑可以锁定它与否,并且无论如何都有效,那么传递一个weak_ptr

作为一个具体的小例子:

mutable std::mutex m_mutex;
mutable std::vector<std::weak_ptr<std::function<void(int)>>> m_callbacks;

void clean_callbacks(int x) {
  auto l = std::unique_lock<std::mutex>(m_mutex);
  auto it = std::remove_if( begin(m_callbacks), end(m_callbacks), [](auto w){ return !w.lock(); } );
  m_callbacks.erase( it, end(m_callbacks) );
}
void call_callbacks() {
  clean_callbacks();
  auto tmp = [&]{
    auto l = std::unique_lock<std::mutex>(m_mutex);
    return m_callbacks;
  }();
  for (auto&& wf:tmp) {
    if(auto sf = wf.lock()) {
      (*sf)(x);
    }
  }
}

clean_callbacks 有一个接受 weak_ptr 的 lambda。它用于删除任何生命周期已结束的m_callbacks

此代码用于一个简单的广播器,其中广播发生的频率远高于侦听器失效的频率,因此等待下一次广播以消除死掉的侦听器是一个不错的策略。

【讨论】:

    【解决方案3】:

    弱指针对于持有以后可能不可用的对象很有用(不会延长它们的生命周期)。这意味着它们通常用于存储在容器(或变量)中。人们通常会传递一个共享指针,直到对象被存储然后转换为弱指针。然后在使用时必须首先将它们转换为共享指针,以检查它们是否仍然有效。因此,除非作为存储和检索过程的一部分,可能在辅助函数中,否则您不太可能传递弱指针。

    【讨论】:

      【解决方案4】:

      在函数中使用 std::weak_ptr 而不是 std::shared_ptr 作为参数的唯一好处是函数负责检查指针是否有效,从而减少任何检查在函数之外。

      bool function(std::weak_ptr _obj)
      {
          if(std::shared_ptr obj = _obj.lock())
          {
              obj->doSomething();
              return true;
          }
          return false
       }
      

      使用 std::shared_ptr 作为参数,不需要检查,但在调用函数之前需要从 std:weak_ptr 转换为 std::shared_ptr。尽管如果存在传递 nullptr 的风险,则也需要进行检查。

      void function(std::shared_ptr _obj)
      {
          _obj->doSomething();
      }
      

      因此,如果从应用程序中的许多不同位置多次将 std::weak_ptr 传递给函数,我想我更愿意将 std::weak_ptr 作为参数,在该函数中进行检查,而不是检查每次在函数之外。自然,您将获得更少的代码行数。

      但是,如果正常传递一个 std::shared_ptr,那么在函数内部自然不需要检查,并且在函数内部检查 std:weak_ptr 是否有效,将是开销。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-26
        • 1970-01-01
        • 2012-08-13
        • 2015-09-03
        • 2013-01-16
        • 1970-01-01
        • 1970-01-01
        • 2017-03-22
        相关资源
        最近更新 更多