Why does weak.lock()
return nullptr
in this code snippest:
std::weak_ptr<int> weakPtr1 = std::make_shared<int>(6);
std::cout << weakPtr1.lock() << std::endl;
whereas it works in the following one:
std::shared_ptr<int> sharedPtr = std::make_shared<int>(99);
std::weak_ptr<int> weakPtr2 = sharedPtr;
std::cout << weakPtr2.lock() << std::endl;
Check cpp.sh/9gkys.
I have thought and thought about it, but I am still confused now. I would be grateful to have some help with this question.
The nullptr keyword is utilized for the null values in the pointer variable. It has its own syntax and representations in the C++ programming language. Let’s see the below syntax code. Above mentioned codes, we can create the function and passing the pointer arguments.
A null shared_ptr does serve the same purpose as a raw null pointer. It might indicate the non-availability of data. However, for the most part, there is no reason for a null shared_ptr to possess a control block or a managed nullptr. But we might utilize a non-empty shared_ptr 's deleter to execute arbitrary cleanup code on block exit.
When it writes NULL, it means the obvious thing: A null pointer. You can translate that into the appropriate construction for the language you are using. For example, for C#, you can use null, or if you are operating in raw IntPtr s, you can use IntPtr.Zero. Bonus chatter: When MSDN says NULL, is it okay to use 0?
Bonus bonus chatter: I’m told that the Visual C++ folks occasionally entertain the possibility of changing the definition of NULL to nullptr, which is permitted by the standard. However, this ends up breaking a lot of code which assumed that NULL is an integral constant evaluating to zero. For example:
Smart pointers, in order to do their work properly, maintain a so called control block which serves as a metadata storage, in particular, use counters. That is, each resource has an associated control block in memory (consisting of e.g. two integers) that smart pointers can refer to to know how many of them are still using/observing the resource. Obviously, each existing std::shared_ptr
increases the use counter stored in the control block, so that its destructor knows whether or not it's time to release the resource on destruction. std::weak_ptr
, in turn, only tracks the object and its control block. Note that here's an important detail: std::weak_ptr
does not increase the use counter. That's desirable, as its main purpose is to break possible cycles between a pair of objects observing one another. That is, if two objects would store std::shared_ptr
s one to another, then such a pair of objects would also keep alive one another endlessly.
How can a std::weak_ptr
know if the resource can be lock()
ed ? This can succeed only if the use counter is greater than zero. It knows that from the control block (which itself remains alive in memory as long as there's also non-zero weak pointers observing it).
In the first example:
std::weak_ptr<int> weakPtr1 = std::make_shared<int>(6);
both a resource (int=6
) is allocated and also its control block. Use counter becomes 1
, and remains so as long as std::shared_ptr
is alive. Then, a std::weak_ptr
is initialized, obtaining a pointer to the control block. Here, it won't increase the use counter. It will, however, increase the counter of weak pointers. At this point, both counters are 1
. Then, at the semicolon ;
, the temporary std::shared_ptr
is destroyed. It decreases the use counter down to 0
. This means there are no more shared pointers sharing ownership of the resource, which allows that resource to be released. However, there is still 1
weak pointer observing the control block, which means the control block itself will remain in the memory, so that weakPtr1
knows it won't be able to lock()
the resource anymore (because that resource no longer exists).
In the second example:
std::shared_ptr<int> sharedPtr = std::make_shared<int>(99);
std::weak_ptr<int> weakPtr2 = sharedPtr;
both the resource int=99
and its control block remain alive. Hence weakPtr2
can be locked as long as sharedPtr
(or any of its copies) is not destroyed.
Your examples use copy initialization. As such, the shared_ptr
constructed on the right lives only until the evaluation of the expression, and is then destroyed:
lock
returns null.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With