I started studying smart pointers of C++11 and I don't see any useful use of std::weak_ptr
. Can someone tell me when std::weak_ptr
is useful/necessary?
相关问题
- Sorting 3 numbers without branching [closed]
- How to compile C++ code in GDB?
- Why does const allow implicit conversion of refere
- thread_local variables initialization
- What uses more memory in c++? An 2 ints or 2 funct
相关文章
- Class layout in C++: Why are members sometimes ord
- How to mock methods return object with deleted cop
- Which is the best way to multiply a large and spar
- C++ default constructor does not initialize pointe
- Selecting only the first few characters in a strin
- What exactly do pointers store? (C++)
- Converting glm::lookat matrix to quaternion and ba
- What is the correct way to declare and use a FILE
Apart from the other already mentioned valid use cases
std::weak_ptr
is an awesome tool in a multithreaded environment, becausestd::shared_ptr
in conjunction withstd::weak_ptr
is safe against dangling pointers - in opposite tostd::unique_ptr
in conjunction with raw pointersstd::weak_ptr::lock()
is an atomic operation (see also About thread-safety of weak_ptr)Consider a task to load all images of a directory (~10.000) simultaneously into memory (e.g. as a thumbnail cache). Obviously the best way to do this is a control thread, which handles and manages the images, and multiple worker threads, which load the images. Now this is an easy task. Here's a very simplified implementation (
join()
etc is omitted, the threads would have to be handled differently in a real implementation etc)But it becomes much more complicated, if you want to interrupt the loading of the images, e.g. because the user has chosen a different directory. Or even if you want to destroy the manager.
You'd need thread communication and have to stop all loader threads, before you may change your
m_imageDatas
field. Otherwise the loaders would carry on loading until all images are done - even if they are already obsolete. In the simplified example, that wouldn't be too hard, but in a real environment things can be much more complicated.The threads would probably be part of a thread pool used by multiple managers, of which some are being stopped, and some aren't etc. The simple parameter
imagesToLoad
would be a locked queue, into which those managers push their image requests from different control threads with the readers popping the requests - in an arbitrary order - at the other end. And so the communication becomes difficult, slow and error-prone. A very elegant way to avoid any additional communication in such cases is to usestd::shared_ptr
in conjunction withstd::weak_ptr
.This implementation is nearly as easy as the first one, doesn't need any additional thread communication, and could be part of a thread pool/queue in a real implementation. Since the expired images are skipped, and non-expired images are processed, the threads never would have to be stopped during normal operation. You could always safely change the path or destroy your managers, since the reader fn checks, if the owning pointer isn't expired.
I see
std::weak_ptr<T>
as a handle to astd::shared_ptr<T>
: It allows me to get thestd::shared_ptr<T>
if it still exists, but it will not extend its lifetime. There are several scenarios when such point of view is useful:Another important scenario is to break cycles in data structures.
Herb Sutter has an excellent talk that explains the best use of language features (in this case smart pointers) to ensure Leak Freedom by Default (meaning: everything clicks in place by construction; you can hardly screw it up). It is a must watch.
std::weak_ptr
is a very good way to solve the dangling pointer problem. By just using raw pointers it is impossible to know if the referenced data has been deallocated or not. Instead, by letting astd::shared_ptr
manage the data, and supplyingstd::weak_ptr
to users of the data, the users can check validity of the data by callingexpired()
orlock()
.You could not do this with
std::shared_ptr
alone, because allstd::shared_ptr
instances share the ownership of the data which is not removed before all instances ofstd::shared_ptr
are removed. Here is an example of how to check for dangling pointer usinglock()
:When we does not want to own the object:
Ex:
In the above class wPtr1 does not own the resource pointed by wPtr1. If the resource is got deleted then wPtr1 is expired.
To avoid circular dependency:
Now if we make the shared_ptr of the class B and A, the use_count of the both pointer is two.
When the shared_ptr goes out od scope the count still remains 1 and hence the A and B object does not gets deleted.
output:
As we can see from the output that A and B pointer are never deleted and hence memory leak.
To avoid such issue just use weak_ptr in class A instead of shared_ptr which makes more sense.
They are useful with Boost.Asio when you are not guaranteed that a target object still exists when an asynchronous handler is invoked. The trick is to bind a
weak_ptr
into the asynchonous handler object, usingstd::bind
or lambda captures.This is a variant of the
self = shared_from_this()
idiom often seen in Boost.Asio examples, where a pending asynchronous handler will not prolong the lifetime of the target object, yet is still safe if the target object is deleted.weak_ptr
is also good to check the correct deletion of an object - especially in unit tests. Typical use case might look like this: