The documentation for std::weak_ptr
on cppreference says this
Effectively returns
expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
, executed atomically.
And my judgement and other SO answers have confirmed that the following is not prone to races
int main() {
auto s_ptr = std::make_shared<T>(...);
auto w_ptr = std::weak_ptr<T>{s_ptr};
auto one = std::thread{[&]() {
auto ptr = w_ptr.lock();
if (ptr) { ... }
}};
s_ptr = std::make_shared<T>(...);
one.join();
}
However can this reliably be used to shadow computation in a program? By shadowing I mean something like this
auto s_ptr = std::make_shared<T>(...);
auto w_ptr = std::weak_ptr<T>{s_ptr};
// thread one
while (...) {
auto ptr = w_ptr.lock();
cout << "Value contained is " << *ptr << endl;
}
// thread two
while (...) {
// do the heavy computation on the side
auto new_value = fetch_new_value();
// then "atomically" swap
s_ptr = std::make_shared<T>(std::move(new_value));
}
The confusing part here is what .lock()
returns. Can it return a nullptr
? All the documentation says is that the operation will be executed atomically. Doesn't say what this mutual exclusion means. Can there be a state in shared_ptr::operator=
where the pointer is null? And can the weak_ptr
access this state? The documentation for shared_ptr::operator=
on cppreference does not seem to mention this.