Is it useful to pass std::weak_ptr to functions?
So is passing
std::weak_ptr
to functions 100% useless?
No.
Consider this toy example.
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";
}
}
};
In this example, a member function observe
keeps the data passed to it. This is often called a "sink parameter".
Its weak_ptr
parameter communicates that this passed pointer is not owning, but reserves the ability to own at a later time, safely detecting if the pointer has expired.
As a different example, a function that doesn't hold state for later could also usefully receive a weak_ptr
parameter in a multithreaded context where the associated data might expire while the function is doing work.
If your clients have a weak_ptr
, and your logic could lock it or not, and is valid regardless, then pass a weak_ptr
.
As a concrete trivial example:
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
has a lambda that takes a weak_ptr
. It is used to remove any m_callbacks
whose lifetime has ended.
This code is used in a simple broadcaster where broadcasts happen far more often than listeners are invalidated, so waiting for the next broadcast to eliminate a dead listener is a good strategy.