将std :: weak_ptr传递给函数是否有用?

时间:2018-12-03 17:47:07

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

我正在阅读赫伯·萨特(Herb Sutter)的this article,该书将智能指针传递给函数。他没有提到std::weak_ptr,老实说,我找不到一个很好的方案来传递这样的智能指针。

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

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

4 个答案:

答案 0 :(得分:9)

  

那么将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参数,在该上下文中关联数据可能会过期,而功能正在起作用。

答案 1 :(得分:3)

如果您的客户有一个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的lambda值是weak_ptr。它用于删除生命周期已结束的任何m_callbacks

此代码用于简单的广播中,其中广播发生的频率远远大于使监听器无效的广播,因此,等待下一个广播以消除无效的监听器是一个好策略。

答案 2 :(得分:1)

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

答案 3 :(得分:0)

使用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是否有效将是开销。

相关问题