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

Posted on 2015-02-12
Last Modified: 2015-02-23

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?

Question by:jxbma
  • 3
LVL 86

Assisted Solution

jkr earned 125 total points
ID: 40607171
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.
LVL 32

Assisted Solution

phoffric earned 250 total points
ID: 40607301
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.
LVL 33

Assisted Solution

sarabande earned 125 total points
ID: 40611343
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.

LVL 32

Expert Comment

ID: 40611607
>> "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.
LVL 32

Accepted Solution

phoffric earned 250 total points
ID: 40611613
>> "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.

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
How to Correctly derive class from CWinThread in MFC 4 64
ejb example issues 3 25
C++ help/ Toy problem 19 29
convert Systemjs to Webpack 3 31
Entering a date in Microsoft Access can be tricky. A typo can cause month and day to be shuffled, entering the day only causes an error, as does entering, say, day 31 in June. This article shows how an inputmask supported by code can help the user a…
If you’re thinking to yourself “That description sounds a lot like two people doing the work that one could accomplish,” you’re not alone.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…

856 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question