Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if weak_ptr is empty (non-assigned)?

Tags:

Is there a way to distinguish between an assigned (possibly expired) weak_ptr and a non-assigned one.

weak_ptr<int> w1; weak_ptr<int> w2 = ...; 

I understand the following checks for either non-assignment or expiry, but is there a (cheaper?) check for only non-assignment?

if (!w.lock()) { /* either not assigned or expired */ } 
like image 208
Zuza Avatar asked Aug 04 '17 12:08

Zuza


People also ask

What is Weak_ptr?

std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr. It must be converted to std::shared_ptr in order to access the referenced object.

How is Weak_ptr implemented?

To implement weak_ptr , the "counter" object stores two different counters: The "use count" is the number of shared_ptr instances pointing to the object. The "weak count" is the number of weak_ptr instances pointing to the object, plus one if the "use count" is still > 0.

Can Weak_ptr be copied?

std::weak_ptr are pointers, so as with any pointer types, a = p; copy pointer, not the content of what is pointed. If you want to copy the content, you would need *a = *p; , but you cannot do that with weak_ptr , you need to lock() both a and p before.

Is Weak_ptr thread safe?

Using weak_ptr and shared_ptr across threads is safe; the weak_ptr/shared_ptr objects themselves aren't thread-safe.


1 Answers

You can use two calls to owner_before to check equality with a default constructed (empty) weak pointer:

template <typename T> bool is_uninitialized(std::weak_ptr<T> const& weak) {     using wt = std::weak_ptr<T>;     return !weak.owner_before(wt{}) && !wt{}.owner_before(weak); } 

This will only return true if w{} "==" weak, where "==" compares owner, and according to en.cppreference.com:

The order is such that two smart pointers compare equivalent only if they are both empty or if they both own the same object, even if the values of the pointers obtained by get() are different (e.g. because they point at different subobjects within the same object).

Since the default constructor constructs an empty weak pointer, this can only return true if weak is also empty. This will not return true if weak has expired.

Looking at the generated assembly (with optimization), this seems pretty optimized:

bool is_uninitialized<int>(std::weak_ptr<int> const&):         cmp     QWORD PTR [rdi+8], 0         sete    al         ret 

... compared to checking weak.expired():

bool check_expired(std::weak_ptr<int> const&):         mov     rdx, QWORD PTR [rdi+8]         mov     eax, 1         test    rdx, rdx         je      .L41         mov     eax, DWORD PTR [rdx+8]         test    eax, eax         sete    al .L41:         rep ret 

... or returning !weak.lock() (~80 lines of assembly).

like image 155
Holt Avatar answered Oct 19 '22 12:10

Holt