What is the best pattern for wrapping a vector of object pointers to objects with C++ smart pointers?


I'm trying to figure out the best pattern for using a shared_ptr wrapped vector<> in C++ (11).
I'm intending on using C++ smart pointers rather than boost.

Consider the following  scenario:
class Point
   int x;
   int y;

vector<Point *> SampleClass::GetPoints()
   vector <Point *> points;
   Point * point1 = new Point(10, 10);
   Point * point2 = new Point(10, 10);


   return points;   

Open in new window

Now in order to prevent memory leak(s), I'd like to wrap this scenario in a smart point.
The vector of points should be a shared_ptr(), as it's client calls will share ownership.

This is what I have so far:
shared_ptr<vector<shared_ptr<Point>>> SampleClass::GetPoints()
   shared_ptr<vector<shared_ptr<Point >>> points = make_shared<vector<shared_ptr<Point>>>();

   shared_ptr<Point> point1 = make_shared<Point>(10, 10);
   shared_ptr<Point> point2 = make_shared<Point>(10, 10);


   return points;   

Open in new window

I'm a little unclear as to what kind of smart pointer each element of the vector should be.
Should it be a unique_ptr<> or a shared_ptr<>?

Is it adequate to have the vector wrapped in a shared_ptr while the elements are unique_ptrs?

What is the best pattern to use in this case?

jxbmaSoftware ConsultantAsked:
Who is Participating?
phoffricConnect With a Mentor Commented:
>> "Is it adequate to have the vector wrapped in a shared_ptr while the elements are unique_ptrs?"
It depends on what your design goals are (which have not been stated).

As mentioned in previous posts, the shared_ptr allows multiple objects to have concurrent access to a shared object without worrying whether the shared object is deleted by one of the accessing objects. This is useful in preventing memory leaks. But it does have the problem in that concurrent access to a shared object is often the source of difficult bugs especially in a multithreaded multicore environment.

To prevent concurrency issues of this nature, you can use unique_ptr.
std::unique_ptr is a smart pointer that retains sole ownership of an object through a pointer and destroys that object when the unique_ptr goes out of scope. No two unique_ptr instances can manage the same object.

Now you still have the memory leak protection without worrying about the shared access issue.

unique_ptr objects own their pointer uniquely: no other facility shall take care of deleting the object, and thus no other managed pointer should point to its managed object, since as soon as they have to, unique_ptr objects delete their managed object without taking into account whether other pointers still point to the same object or not, and thus leaving any other pointers that point there as pointing to an invalid location.
jkrConnect With a Mentor Commented:
I've been starting to scratch my head regarding your recent Qs about smart pointers recently, and right now that seems like overkill to me, except when you are in a scenario where myriads of Point objects are added and removed in a highly dynamical way. As a rule of thumb, the best way to avoid memory leaks is to not store pointers in containers at all, but rather instances. This saves you from the overhead of memory management once you have properly created assignment operators and copy constructors (which, BTW, is not necessary in the above scenario, the compiler provided ones will suffice). So, unless you have a good reason for storing pointers in that manner - stay away from it.
phoffricConnect With a Mentor Commented:
The choice of smart pointers depends on your requirements and design as jkr stated. Without a good reason, why complicate your code unnecessarily.

Avoiding passing an entire vector to the caller in a return statement is smart.
But still, I believe that your approach to avoid that is overkill.
(I assumed that was your intent when you chose a smart pointer to a vector of smart pointers, rather than just a vector of smart pointers.)

Using smart pointers similar to your version is sometimes used to allow a reader thread to release its RW lock more quickly even though a delete thread might delete the vector entry while the reader thread, after it got access to the smart pointer to the point, is accessing the Point.

But every case is different. There are multiple chapters in books on good smart pointer usage, so here is a wiki link just to be more complete.
sarabandeConnect With a Mentor Commented:
to add to above comments:

i strongly support what was said regarding to keep it simple and not use pointers if not necessary. smart pointers help to avoid leaks but you can still have two smart pointers pointing to the same 'physical' object. smart pointers do not automatically prevent from using copies which would allow to change an object while the copy remains unchanged.

a method which doesn't use smart pointers but nevertheless reliably could avoid memory leaks is to using a self-made 'smart' container class. the container uses a std::vector which contains all objects of the class. if you don't use multiple classes by baseclass you should store objects in the vector (see comment of jkr). otherwise you have to store the base class pointer in the vector. additionally, you were using one or more maps in order to get quick access to the objects by key. if the keys are not unique you either use multimaps or vectors for the data such that one key can point to multiple data.

you would create all your objects by using the 'smart' container. it would provide functions to create objects and would put the object or its pointer to the 'all' vector and then create the entries for the additional maps which refer to the object in the vectory by storing the pointer. if you want to delete an object you have to erase its references from the maps and finally erase the object from the vector. when using pointers, the pointer safely can deleted. if you want to delete all objects, you safely can clear the maps and finally delete (clear) all entries of the vector.

all this could be encapsulated into the smart container where the interface contains objects and references to objects rather than pointers. additionally, you easily could add thread-safety if required.

>> "you can still have two smart pointers pointing to the same 'physical' object"
Yes. with smart pointer this can happen, and it means that you are sharing an object amongst other instances. If multithreaded or multicore environment, this becomes an even more difficult problem to analyze. In this case, you want to guard against the same 'physical' object from being modified partly by one object and before that operation completes, another object comes in and modifies the same shared 'physical' object. One way to protect against that is to use a mutex thereby allowing only one of the sharing objects access to the shared object at a time.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.