Solved

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

Posted on 2015-02-12
5
200 Views
Last Modified: 2015-02-23
Hi:

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);

   points->push_back(point1);
   points->push_back(point2);

   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);

   points->push_back(point1);
   points->push_back(point2);

   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?

Thanks,
JohnB
0
Comment
Question by:jxbma
  • 3
5 Comments
 
LVL 86

Assisted Solution

by:jkr
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.
0
 
LVL 32

Assisted Solution

by:phoffric
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.
http://en.wikipedia.org/wiki/Smart_pointer#C.2B.2B_smart_pointers
0
 
LVL 32

Assisted Solution

by:sarabande
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.

Sara
0
 
LVL 32

Expert Comment

by:phoffric
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.
0
 
LVL 32

Accepted Solution

by:
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.
http://en.cppreference.com/w/cpp/memory/unique_ptr

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.
http://www.cplusplus.com/reference/memory/unique_ptr/
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
changeXy challenge 13 57
creating threads in delphi 1 54
C# Error - Add Failed 12 39
Adoquery sql  left join does not work 25 46
Displaying an arrayList in a listView using the default adapter is rarely the best solution. To get full control of your display data, and to be able to refresh it after editing, requires the use of a custom adapter.
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
In this fifth video of the Xpdf series, we discuss and demonstrate the PDFdetach utility, which is able to list and, more importantly, extract attachments that are embedded in PDF files. It does this via a command line interface, making it suitable …

758 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now