Skip to main content
GameDev.net gamedev.net
🔒 Locked

std::vector , how does it free resources?

Started by jujumbura Dec 12, 2005 at 5:04 PM 9 replies 1.2k views
Original Post
jujumbura
jujumbura
My question is this: Suppose I use a vector in an arbitrary function like so, std::vector vec; myclass *tempclass = new myclass; vec.push_back( *tempclass ); When the vector is destroyed ( from the stack returning ), will the memory from the "new myclass" be freed up automatically? Or will I have a memory leak? If this causes a memory leak, what is the proper way to use a vector with dynamically allocated memory? Thanks much, jujumbura
dave
dave
No, you have to iterate through and cleanup those pointers yourself. containers store by value and have no idea what is being stored.
jujumbura
jujumbura
By value? But the definition of push_back says:

void push_back( const TYPE& val );

Doesn't that mean it's storing by reference?
dave
dave
Quote:
Original post by jujumbura
By value? But the definition of push_back says:

void push_back( const TYPE& val );

Doesn't that mean it's storing by reference?


It still makes a local copy of the item, just because you are passing it by reference doesn't mean that it is storing by reference. And if it was storing by reference something you add could go out of scope and your container is corrupt.
ViLiO
ViLiO
for(int i=0; i<(int)vec.size(); ++i){   delete vec;}
Richard 'ViLiO' Thomasv.net | Twitter | YouTube
Fruny
Fruny
Quote:
Original post by jujumbura
When the vector is destroyed ( from the stack returning ), will the memory from the "new myclass" be freed up automatically? Or will I have a memory leak? If this causes a memory leak, what is the proper way to use a vector with dynamically allocated memory?


The rule is, as always, to deallocate what you allocated. std::vector will clean up after itself, but it cannot clean up after you. Indeed, how could it differenciate myclass a; vec.push_back(&a);, where trying to release the memory would be an error, from vec.push_back(new myclass); where it is necessary to call delete, or even from vec.push_back(new myclass[20]);, where it is necessary to call delete[].

Even if you limit yourself to dynamically allocated objects, there might be other pointers to the object in the vector in existence somewhere else in your program. If the vector were to delete the object, those pointers would be left pointing to invalid memory (dangling pointer).

The only rational decision is thus for vector not to delete the objects and to let you decide. If it were to take the decision out of your hands, it would limit its applicability.

There are workarounds for the unwieldiness of having to delete the objects yourself. The first is to rely on smart pointers (e.g. boost::shared_ptr), which keep track of whether the object should be deleted or not (and how) based (typically) on a reference count. When the vector gets destroyed, the smart pointers' reference counts will go down, and those objects which aren't accessible anymore will be destroyed (unless you have a reference cycle, which should obviously be avoided).

To present it in another light, upon destruction, the vector destroys its elements and releases its own memory. Unlike raw pointers, smart pointers do have a destructor, meaning that cleanup can happend when the pointers themselves are destroyed. Raw pointers, being basic types, do not have destructors, and the pointed object (thankfully) isn't affected in any way by the pointer's "destruction". Which means that the pointees aren't destroyed when the vector is destroyed.

The other workaround would be to use something like Boost's pointer containers, which use pointers internally, thus enabling polymorphism, while still maintaining ownership semantics: when you remove the object from the container, it is destroyed, as if it had been stored "by value" in the container.

Which solution is appropriate depends on the reason why you are using pointers in the first place, and how you plan on using the container.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
jujumbura
jujumbura
Ok, that makes sense, thanks.

So really, I don't need to call new at all. If in my function I just make a temporary object, initiate it to the way I want and then pass it to push_back, vector will make a copy and hold on to it. The temporary object will get destroyed when the function returns, but if the vector is an instance variable, it will stick around until the object who owns it is destroyed.

And since the vector just holds a bunch of copied objects instead of pointers, I don't need to release anything. Right?
Fruny
Fruny
Quote:
Original post by jujumbura
So really, I don't need to call new at all.


Indeed, and I had misread your code (thought about vectors of pointers). In your example, calling new here is rather misguided. You'd be much better off using an unnamed temporary: vec.push_back( myclass() ); or a local variable.

Quote:
And since the vector just holds a bunch of copied objects instead of pointers, I don't need to release anything. Right?


For a vector of objects with value semantics (i.e. can be copied correctly, have destructors if needed, etc), no, you don't have anything to release. It'll be done automatically.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
jujumbura
jujumbura
Hrm. Ok, well here's the kicker. The objects I'd like to store are subclasses of an abstract class. So since the abstract class cannot be constructed, it looks like I cannot make a vector of type baseclass. Which limits its usefulness.

So is the only way to get polymorphism from an abstract base class in a vector to store baseclass pointers, and then cleanup the memory after I'm done?

dave
dave
Yeah that is how it wil have to be done.
Fruny
Fruny
Quote:
Original post by jujumbura
So is the only way to get polymorphism from an abstract base class in a vector to store baseclass pointers, and then cleanup the memory after I'm done?


Check the alternatives I offered.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.