将 std::weak_ptr 传递给函数有用吗?
Is it useful to pass std::weak_ptr to functions?
我正在阅读 Herb Sutter 的 this article 关于将智能指针传递给函数的内容。他没有提到 std::weak_ptr
老实说,我找不到传递这种智能指针有用的好场景。
函数是否拥有所有权?通过std::shared_ptr
。函数是否只需要对底层对象进行操作?传递原始指针或引用。
那么将 std::weak_ptr
传递给函数是否 100% 没用?
如果您的客户有 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
。
此代码用于一个简单的广播器,其中广播发生的频率远高于听众失效的频率,因此等待下一次广播以消除死听众是一个很好的策略。
So is passing std::weak_ptr
to functions 100% useless?
没有
考虑这个玩具示例。
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
参数,其中关联的数据 可能会在函数运行时过期。
弱指针可用于保留以后可能不可用的对象(无需延长其生命周期)。这意味着它们通常用于存储在容器(或变量)中。人们通常会传递一个共享指针,直到对象被存储,然后转换为弱指针。然后在使用时必须首先将它们转换为共享指针,以检查它们是否仍然有效。因此,除非作为存储和检索过程的一部分(可能在辅助函数中),否则您不太可能传递弱指针。
我能想出的唯一好处是在函数中使用 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是否有效,将是开销。
我正在阅读 Herb Sutter 的 this article 关于将智能指针传递给函数的内容。他没有提到 std::weak_ptr
老实说,我找不到传递这种智能指针有用的好场景。
函数是否拥有所有权?通过std::shared_ptr
。函数是否只需要对底层对象进行操作?传递原始指针或引用。
那么将 std::weak_ptr
传递给函数是否 100% 没用?
如果您的客户有 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
。
此代码用于一个简单的广播器,其中广播发生的频率远高于听众失效的频率,因此等待下一次广播以消除死听众是一个很好的策略。
So is passing
std::weak_ptr
to functions 100% useless?
没有
考虑这个玩具示例。
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
参数,其中关联的数据 可能会在函数运行时过期。
弱指针可用于保留以后可能不可用的对象(无需延长其生命周期)。这意味着它们通常用于存储在容器(或变量)中。人们通常会传递一个共享指针,直到对象被存储,然后转换为弱指针。然后在使用时必须首先将它们转换为共享指针,以检查它们是否仍然有效。因此,除非作为存储和检索过程的一部分(可能在辅助函数中),否则您不太可能传递弱指针。
我能想出的唯一好处是在函数中使用 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是否有效,将是开销。