Sign in to follow this  

what happens when a container of pointers is destroyed, are pointers destroyed?

This topic is 3778 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Just a simple question: If I create something like: std::string my_function() { std::vector<some_pointer*> pVec; pVec.push_back(new some_pointer); pVec.push_back(new some_pointer); pVec.push_back(new some_pointer); <some action that uses pVec and produces a std::string result> return result; } When pVec goes out of scope, what happens to the pointers? Are they destroyed too?

Share this post


Link to post
Share on other sites
Just to clarify some terminology the pointers are destroyed, its the pointed at things which aren't destroyed. (sorry, it just seems people mix the two together all the time)

Share this post


Link to post
Share on other sites
... But please, first be sure that you can't (and know why not) just simplify:


std::string my_function()
{
std::vector<some_class> vec;
vec.push_back(some_class());
vec.push_back(some_class());
vec.push_back(some_class());

<some action that uses vec and produces a std::string result>

return result;
}

Share this post


Link to post
Share on other sites
Hi Zahlman,

I don't have a choice (I don't think). I typically avoid pointers like the plague, but in this case I need dynamic allocation because I will load data files that may vary in size between runs and need to size the vector dynamically at runtime.

Share this post


Link to post
Share on other sites
That doesn't mean you need to use pointers -- you're probably thinking of how you'd have to handle it if you didn't have vector. vector's resizable; this will work fine:

int count = readNumberOfThingsFromFile();

std::vector<Thing> things; // No pointers!
things.reserve(count);

for(int i = 0; i < count; ++i)
{
Thing thing = readThingFromFile();
things.push_back(thing);
}


If you don't know the size beforehand, it will still work, you will just have to omit the reserve() call which will cause a (entirely trivial here) perf issue since more reallocations of the underlying memory will occur.

Share this post


Link to post
Share on other sites
If it helps, write the following on a post-it note and stick it to your monitor:

The main reason I am using standard library containers is so that they can do the memory management for me.

Share this post


Link to post
Share on other sites
Just to echo some good advice..
In the future, if you ever find yourself in the situation where you do need a vector of pointers then there's an all too often overlooked problem (and people who write their own array classes instead of using the one that comes with the language usually fall foul of this too): The problem is 'exceptions'.

If an exception is thrown during a new call (either because the allocation failed or because the constructed class throws an exception in its constructor) then the stack will unwind and the vector will de-allocate its own memory thus any previously 'newed' objects that were pointed to in the vector will not be destroyed.

As has already been mentioned smart pointers come to the rescue, if the stack unwinds the smart pointers will be destructed when the vector is and the smart pointers will automatically deallocate the object they pointed to.

Share this post


Link to post
Share on other sites
Thanks D,

That's really useful info. I did write an array class at one time and I've also tried to extend some of the basic STL types, but I quickly discovered that there can be untold complications when trying to do these things. Far easier (and safer) just to use the STL and take advantage of memory management, excellent algorithmic techniques, cross-platform applicability etc. These days I'm using them a lot more within namespace-protected functions and for composition as opposed to inheritance (since there are a lot of drawbacks there, particularly no virtual destructors), rather than trying to extend or adapt.

From what I can see, one way that a vector would legitimately contain pointers is where it contains objects based upon an abstract data class; are there other times pointers could be recommended?

Share this post


Link to post
Share on other sites
Yes, there can be many occasions...

In order for an object to be placed into an STL container it must be copy-assignable. Not all objects allow this, so using a container of pointers is a good way around it.

Also what about when you need a container of objects and you wish to either move objects around within the container (like for sorting) or to move them between two containers. This can be achieved without pointers but requires copying the object and destroying the old one (expensive if the object is large). Using pointers makes doing this very cheap compared with dealing with large objects.

There are many libraries out there that return all sorts of different things by-reference (pointer) rather than by-value, clearly if you wanted to store these in an STL container then storing the pointers is the only way.

N.B. As for my post about exceptions and smart-pointers, if for some reason you didnt want to use smart-pointers (Maybe concerned with performance before profiling [wink]) you could always just make sure you catch any exceptions then release all your allocated memory manually and re-throw the exception.

Share this post


Link to post
Share on other sites
Quote:
Original post by random_thinker
From what I can see, one way that a vector would legitimately contain pointers is where it contains objects based upon an abstract data class


Yes, although you might also consider making wrappers based on the Pimpl idiom (likely using a smart pointer to indirect the implementation).

Quote:
are there other times pointers could be recommended?


The other typical use case is when you need to refer to already-existing objects held somewhere else, and/or keep multiple copies of the same object in the container (e.g. making a D&D-type RPG, you might have something somewhere like std::vector<Player*> initiativeOrder;). In these cases you need to think very carefully about the "ownership" of the pointed-at things. Sometimes the correct solution is to only keep "weak" pointers in the vector; i.e. only ever let them point at already-existing things, and never do any allocation or deallocation based on pointers stored in/retrieved from that vector. In more complicated cases, smart pointers - typically reference-counted ones such as boost::shared_ptr - are very useful.

Share this post


Link to post
Share on other sites

This topic is 3778 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this