What is the diffrence between lock () and expired ()? weak_ptr C ++

I recently started working in C ++ 11. I learned about weak_ptr . There are two ways to get a raw pointer.

  • lock() Function

     shared_ptr<Foo> spFoo = wpPtr.lock(); if(spFoo) { spFoo->DoSomething(); } 
  • expired() function

     if(!wpPtr.expired()) { shared_ptr<Foo> spFoo = wpPtr.lock(); spFoo->DoSomething(); } 

Which one is better? What is the difference between the two methods?

+4
source share
5 answers

Thus, the common ptr and weak ptr are thread safe, if you have an instance of an object local to the given stream, and they have a common object with a pointed object, you can interact with it in one stream, and the other is all works.

For this to work correctly, you must use them correctly.

wp.expired() is only useful to do things like "delete every expired weak ptr from the buffer". This is not useful for your purpose.

Every weak pointer that has expired has expired. But the weak pointer involved can become inactive after you check it.

 if(!wpPtr.expired()) { // <<--- here shared_ptr<Foo> spFoo = wpPtr.lock(); spFoo->DoSomething(); } 

In <<--- here we do not know anything about the state of wpPtr in a multi-threaded environment. It may be expired or not expired. On the other hand:

 if(wpPtr.expired()) { // <<--- there } 

In <<--- there we know that the weak pointer has expired.

As with the io file and other types of transactional operations, the only way to check if you can do something is to try it. Between the definition, you should be able to do it and do it, the state may change, and the operation may fail.

Sometimes you can decide that you almost certainly could not do it before, which is sometimes useful, but you cannot be sure that you can do it until you try. An attempted attempt may fail, after which you process the error.

 if(auto spFoo = wpPtr.lock()) { spFoo->DoSomething(); } 

this is the “right” way to interact with a weak pointer. Check the validity of the weak pointer and get a generic pointer in the same operation.

Creating spFoo outside the if() header is acceptable, I prefer this method, since the scope of spFoo limited to the exact scope where it is valid.

Another preferred method is an early exit where you wrote your code as SFINAE friendly:

 auto spFoo = wpPtr.lock(); if(!spFoo) return error("wp empty"); spFoo->DoSomething(); 

which makes the "expected" execution of the code stream in a flat line without indentation or conditions or transitions.

+7
source

The second option has two problems:

  • Performs unnecessary wpPtr.expired() validation
  • Missing required if (spFoo) check before spFoo dereferencing

The first option is transactional, and it is used when you ultimately need to work with an object referenced by a weak pointer.

+4
source

Option 1

If you go with option 2, then between the calls to wpPtr.expired() and the call to wpPtr.lock() the weak_ptr may expire, and the line spFoo->DoSomething() will try to dereference the shared_ptr zero.

+2
source

For a quote from cppreference.com :

std::weak::lock effectively returns

 expired() ? shared_ptr<T>() : shared_ptr<T>(*this) 
Validity

expired to check if the underlying object is valid and blocks the potential promotion of the object to std::shared_ptr

0
source

Below are the corresponding operations for weak_ptr . You have to go with option 1 because approach 2 is not thread safe.

w.use_count() The number of shared_ptr sharing the ownership of w

w.expired() returns true if w.use_count() is zero, false otherwise

w.lock() If expired is true , returns null shared_ptr ; otherwise returns a shared_ptr object pointed to by w .

(2) Unsafe

 // let p be the last shared_ptr pointing at the same object as wpPtr if (!wpPtr.expired()) { // we enter the if-statement because wpPtr.use_count() is 1 // p goes out of scope on its thread, the object gets deleted shared_ptr<Foo> spFoo = wpPtr.lock(); // null shared_ptr spFoo->DoSomething(); // ERROR! deferencing null pointer } 

(1) Thread-safe

 // let p be the last shared_ptr pointing at the same object as wpPtr shared_ptr<Foo> spFoo = wpPtr.lock(); // now, wpPtr.use_count() is 2, because spFoo and p are both pointing at the object // p goes out of scope on its thread, but spFoo is still pointing at the object if(spFoo) { spFoo->DoSomething(); // OK! safe to dereference } 
0
source

All Articles