Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use shared_ptr or weak_ptr on not mainly containers?

I have two std containers. Both of them with pointers to the same data structure. The first containing all the data and the second one containing only some of the same data. Should I use shared_ptr or weak_ptr on the second container?

Firstly, when I read the reference I thought about using unique_ptr on the first collection. My first collection contains all the data and it's the only one that "owns". Meaning that if the data is not there it should be deleted. But then when I try to create the second collection I didn't know what to do. I created a unique pointer but now I need another pointer to the same element destroying uniqueness, but in fact the real owner was not the new pointer. So I understood (I hope I'm not wrong) that the uniqueness is on the way of reaching elements and not (e.g.) the possibility of delete it. So, shared_ptr. I have them on my first collection. But now the second one comes up, I thought to use shared_ptr here too. The ways to access the same data could be both, so the owners are two. But in my case the data is always deleted from the second before. And if I use a weak_ptr , the number of owners will not increase. In both cases the element will be deleted when the first collection wants. At the end I'm using shared_ptr because with weak_ptr I need to lock() every pointer in every line of code, making it less readable. But what should I really use?

like image 314
Umuril Lyerood Avatar asked Aug 03 '15 01:08

Umuril Lyerood


People also ask

When should I use weak_ptr?

By using a weak_ptr , you can create a shared_ptr that joins to an existing set of related instances, but only if the underlying memory resource is still valid. A weak_ptr itself does not participate in the reference counting, and therefore, it cannot prevent the reference count from going to zero.

Why would you choose shared_ptr instead of unique_ptr?

Use unique_ptr when you want to have single ownership(Exclusive) of the resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. A shared_ptr is a container for raw pointers.

Should I use smart pointers everywhere?

You should not use smart pointers when you want to pass a reference to an object to a function and the function does not destroy or prevents the destruction of the object. In other words, if the function does not participate in the lifecycle of the passed object. For example: #include <iostream>

When should I use smart pointer?

Smart pointers should be preferred over raw pointers. If you feel you need to use pointers (first consider if you really do), you would normally want to use a smart pointer as this can alleviate many of the problems with raw pointers, mainly forgetting to delete the object and leaking memory.


2 Answers

It doesn't sound like you need std::shared_ptr because your data is owned in one place.

I would recommend using std::unique_ptr in the owning container and then simply put the raw pointers in the second and subsequent containers.

This works because you will never delete the raw pointers but the data they point to is still managed by a smart pointer and so will be released when you no longer need it.

Despite some bad press, raw pointers are perfectly respectable when used as non owning accessors to data that is owned by some other entity that will delete it at the appropriate time.

like image 157
Galik Avatar answered Nov 19 '22 20:11

Galik


You haven't given a critical piece of information, which is whether you can guarantee that the two collections have the same lifetime or not. If you can guarantee that both collections have the same lifetime, then using unique_ptr for the collection that owns everything and raw pointers for the other (as @Galik suggests) is ideal.

If you cannot guarantee that the two lifetimes match, then whether you select shared_ptr's for both or shared_ptr for the first and weak for the second depends on when you want the objects to be destroyed. It sounds like only the first collection is a true owner, so you'd want weak pointers.

However, I'd heavily recommend that you stick with the first approach. It's much cleaner to avoid shared_ptr and weak_ptr. The danger is that if your two collections have different lifetimes, the first collection can be destroyed before the second (just a single misplaced brace), and then when the second collection tries to access, it has dangling pointers. You can of course simply be careful with your variables, but guaranteeing that two independent local variables consistently have the same lifetime is surprisingly easy to mess up.

If you make both collections elements of the same class, you guarantee that they get constructed and destructed at the same time. The exact details of what that class should look like and which code should go where depends on the details of your problem, of course. But even something as simple (albeit bizarre) as making them both the only members (and public) of the same struct is better than using two local variables.

like image 41
Nir Friedman Avatar answered Nov 19 '22 22:11

Nir Friedman