I'm in a case where i use a builder to use factory to create CombatUnit for my project, as show in the schema (please note that I have an abstract factory, but i wouldn't complexify it for nothing).
The thing is, i'm creating arrays of arrays and i'm using unique_ptr to protect from memory leaks.
But i can't find if i'm overusing smart_pointer for nothing, here why
std::unique_ptr<std::vector<std::unique_ptr<std::vector<std::unique_ptr<CombatObject>>>>>& Builder_FleetsCombatObjects::BuildFleets(const std::vector<const CombatObject::ConstructionOrder_CombatObject>& orders)
{
std::unique_ptr<std::vector<std::unique_ptr<std::vector<std::unique_ptr<CombatObject>>>>> fleets(new std::vector<std::unique_ptr<std::vector<std::unique_ptr<CombatObject>>>>());
Factory_Mechas mFact;
Factory_SpaceShip sFact;
for (auto order : orders)/* No Abstract factory to match schema */
{
if (sFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets->push_back(sFact.CreateSpaceShip(order));
}
else if (mFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets->push_back(mFact.CreateMechas(order));
}
}
return fleets;
}
From my actual perspective it's not overdoing it, even if smart_pointer are heavier and slower (in general use i mean), each unique_ptr will make sure that the sub smart_pointer "deleter" will be called.
But somehow i can't feel it's right, like i'm not understanding well how smartpointer work.
Shouldn't vector "make sure" sub vector are "free"? then i could reduce to : std::unique_ptr<std::vector<std::vector<std::unique_ptr<CombatObject>>>>&
Or even std::vector<std::vector<std::unique_ptr<CombatObject>>> if vector are memory managed in c++19.
I'm not sure of what i understand, can you help me?
C++ is Unique_ptr pertinent for vectors of vectors
That's for you to decide, but only rapidly looking at the code without other knowledge of the infrastructure, I would say that this is a heavy, terrible code smell. I would simply use the vector as is. It's lighter, safer, simpler, and faster.
A pointer to a STL containe is usually a strong indicator of code smell, and a pointer to a STL container that contains pointer to STL containers has even a stronger code smell. This would simply not pass review and I would urge to simplify.
Owning pointers to STL containers should practically not exist in a code, unless there is some class that encapsulate very special memory management through container pointers, but they should not escape that class. And even then, you can manage memory and reuse with simple container values.
You should give value semantics a try! It helps local thinking and usually make code simpler.
Now for the non opinion based part of the question.
Let's drop the superfluous unique pointers in your code so it's easier to explain:
std::vector<std::vector<std::unique_ptr<CombatObject>>>& Builder_FleetsCombatObjects::BuildFleets(const std::vector<const CombatObject::ConstructionOrder_CombatObject>& orders)
{
std::vector<std::vector<std::unique_ptr<CombatObject>>> fleets{};
Factory_Mechas mFact;
Factory_SpaceShip sFact;
for (auto order : orders)/* No Abstract factory to match schema */
{
if (sFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets.push_back(sFact.CreateSpaceShip(order));
}
else if (mFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets.push_back(mFact.CreateMechas(order));
}
}
return fleets;
}
In this code, we copy and construct new vectors, and also allocate new unique pointers.
Here, your question would become: How to make sure a vector of vector of unique pointer is freed?
Well, let's start by looking at a vector of integer:
{
std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
}
// Did we leaked?
Here, we did not leaked. This is because the vector is responsible to allocate, and also deallocate. It will deallocate old buffers when pushing back, and will deallocate when the vector goes out of scope.
Now what about a unique pointer?
{
std::unique_ptr<int> ptr = std::make_unique<int>(3);
*ptr = 1;
} // Did we leaked?
Now did we leaked? No. That would be quite absurd!
Now let's try copying these two types:
std::vector<int> vec;
std::unique_ptr<int> ptr = std::make_unique<int>(3);
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
// Copy!
std::vector<int> vec2 = vec;
std::unique_ptr<int> ptr2 = ptr; // Uh oh! Error!
Here as you can see, you cannot copy the unique pointer. Copying a unique pointer won't compile.
However, you can copy a vector, so what's happening when you copy a vector of unique pointer?
std::vector<std::unique_ptr<int>> vec_ptr;
vec_ptr.push_back(std::make_unique<int>(1));
vec_ptr.push_back(std::make_unique<int>(2));
vec_ptr.push_back(std::make_unique<int>(3));
std::vector<std::unique_ptr<int>> vec_ptr2 = vec_ptr; // Error again!
Here it still won't compile! That is because to create a copy of the buffer, you need to copy each elements. If the elements cannot be copied, you cannot copy the vector, so the vector is not copiable.
Now since a vector manage the memory completely, and that unique ptr manages the memory completely, you cannot leak any memory unless you explicitly ask the unique pointer to drop ownership:
std::unique_ptr<int> ptr = std::make_unique<int>(3);
int* raw_owning_pointer = ptr.release();
// Here, I have to delete it myself
Now in your code, no matter the push backs and the unique pointer and vector combination, there is no leak!
To be really sure that there is no leak at all, use a sanitizer, or a memory debugger such as valgrind.
Related
I was thinking about a this situation not for a real implementation but to understand better how pointers works.
class foo(){
foo();
~foo();
void doComplexThings(const std::vector<int*>& v){
int* copy;
for(int i = 0; i < v.size(); i++){
copy = v[i];
// do some stuffs
}
}
}
main(){
std::vector<int*> myVector; // suppose we have 100 elements
doComplexThings(myVector);
for(int i = 0; i < myVector.size(); i++){
delete myVector[i];
}
myVector.clear();
}
Ok, I know that have no sense to copy v[i] inside an other pointer, but I was thinking: copy do a memory leak?
After the execution of doComplexThings(), copy will continue to exist and will occupy space in the heap?
After deleting all elements it will continue to exist and point to a deallocated memory?
So logically if I do this things with complex objects I'll keep occupy the memory with unreference object? Or copy is saved in the stack because I don't use new? And at the end of doComplexThings it will be deleted?
I'm a bit confused, thanks!
There is some confusion on the topic of pointers in the C++ community. While it is true that smart pointers have been added to the library to alleviate problems with dynamic memory allocation, raw pointers are not obsolete. In fact, whenever you want to inspect another object without owning it, you should use a reference or raw pointer, depending on which suits your needs. If the concept of ownership is unclear to you, think of an object as being owned by another object if the latter is responsible for cleaning up afterwards (deleting the former).
For example most uses of new and delete should be replaces with the following (omitting std for brevity):
{
auto ptr_to_T = make_unique<T>(//constructor params);
do_stuff_with_smart_ptr(ptr_to_T);
do_stuff_with_T(*ptr_to_T);
do_stuff_with_raw_ptr(ptr_to_T.get());
} // automatic release of memory allocated with make_unique()
Notice how a function that takes a T* doesn't need a smart pointer if it doesn't keep a copy of the T* it is given, because it doesn't affect the lifetime of the object. The object is guaranteed to be alive past the return point of do_stuff_with_T() and its function signature signals that it doesn't own the object by taking a raw pointer.
On the other hand, if you need to pass the pointer to an object that is allowed to keep the pointer and reference it later, it is unclear when the object will need to be destroyed and most importantly by whom. This is solved via a shared pointer.
ClassThatNeedsSharedOwnership shared_owner;
{
auto ptr_to_T = make_shared<T>(//constructor params);
shared_owner.set_T(ptr_to_T);
// do a lot of stuff
}
// At this point ptr_to_T is destroyed, but shared_owner might keep the object alive
So how does the above factor in to your code. First of all, if the vector is supposed to own (keep alive) the ints it points to, it needs to hold unique_ptr<int> or shared_ptr<int>. If it is just pointing to ints held by something else, and they are guaranteed to be alive until after the vector is destroyed, you are fine with int*. In this case, it should be evident that a delete is never necessary, because by definition your vector and the function working on the vector are not responsible for cleaning-up!
Finally, you can make your code more readable by changing the loop to this (C++11 which you've tagged in the post):
for (auto copy : v){
// equivalent to your i-indexed loop with copy = v[i];
// as long as you don't need the value of i
do_stuff_to_int_ptr(copy);
// no delete, we don't own the pointee
}
Again this is only true if some other object holds the ints and releases them, or they are on the stack but guaranteed to be alive for the whole lifetime of vector<int*> that points to them.
No additional memory is allocated on the heap when you do this:
copy = v[i];
variable copy points to the same address as v[i], but no additional array is allocated, so there would be no memory leak.
A better way of dealing with the situation is to avoid raw pointers in favor of C++ smart pointers or containers:
std::vector<std::vector<int>> myVector;
Now you can remove the deletion loop, which is an incorrect way of doing it for arrays allocated with new int[length] - it should use delete[] instead:
delete[] myVector[i];
Basically you're illustrating the problem with C pointers which lead to the introduction of C++ unique and shared pointers. If you pass a vector of allocated pointers to an opaque member function, you've no way of knowing whether that function hangs onto them or not, so you don't know whether to delete the pointer. In fact in your example you don't seem to, "copy" goes out of scope.
The real answer is that you should only seldom use allocated pointers in C++ at all. The stl vector will serve as a safer, easier to use version of malloc / new. Then you should pass them about as const & to prevent functions from changing them. If you do need an allocated pointer, make one unique_ptr() and then you know that the unique_ptr() is the "owner" of the memory.
I have had a good look at some other questions on this topic and none of them (to my knowledge) address how to correctly erase items from a stl list of objects which contain dynamicically assigned memory vs. a stl list of objects that don't contain dynamically assigned memory.
I want to use a list of objects. Take this object for example (which contains no dynamically assigned memory):
class MyPoint {
public:
MyPoint(int _x,int _y)
{
x = _x;
y = _y;
}
private:
int x;
int y;
};
So I might create a list of objects (not pointers to them), add things to it and then erase an element:
list<MyPoint> myList;
myList.push_back(MyPoint(3,4));
myList.push_back(MyPoint(1,2));
myList.push_back(MyPoint(8,8));
myList.push_back(MyPoint(-1,2));
list<MyPoint>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
My list now contains:
(3, 4)
(1, 2)
(-1, 2)
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
Ok, now consider an alternative version of the class that allowed a point in N-dimensional space. I.e., I could dynamically assign an array of length N to hold the N points inside the class (I have spared you the implementation as that is not in question here). The destructor of the class would then delete the dynamically assigned array using 'delete'.
class MyDynamicPoint {
public:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete points;
points = NULL;
}
private:
int *points;
};
I might now create a list of pointers to the objects, instead of the objects themselves:
list<MyDynamicPoint*> myList;
myList.push_back(new MyDynamicPoint(8));
myList.push_back(new MyDynamicPoint(10));
myList.push_back(new MyDynamicPoint(2));
myList.push_back(new MyDynamicPoint(50));
list<MyDynamicPoint*>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
QUESTION 2a - Is the above correct? I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Many thanks in advance for any help,
Best,
Adam
When you have a class with data members that have automatic storage duration (i.e. their lifetime is tied to the instance of this class) like this:
class MyPoint {
private:
int x;
int y;
};
and you will use list<MyPoint> myList;, then this instance of std::list is also an object with automatic storage duration, that will be cleaned up automatically and by the time the container is destructed, so are the elements it holds. Everything is taken care of.
But the latter version is not very lucky choice... not only that you have a container holding pointers, you even decided to create a data member of class Point that will be allocated dynamically. At first note that everything that has been allocated by calling new should be freed by calling delete and everything allocating by calling new[] should be freed by calling delete[].
In this situation, you are allocating the memory when the object is constructed and cleaning it up when the object is destructed:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete[] points;
points = NULL;
}
private:
int *points;
You would achieve the same by using some std::vector or std::array instead of the C-style array and you wouldn't have to take care of the memory management on your own:
MyDynamicPoint(int N) : points(std::vector<int>(N, 0)) { }
private:
std::vector<int> points;
the std::vector object will take care of memory management for you.
And last thing: when you dynamically allocate an element and store it into the container:
myList.push_back(new MyDynamicPoint(8));
you need to free this memory on your own, erasing the pointer from the list is not enough:
list<MyDynamicPoint*>::iterator it;
...
delete *it;
myList.erase(it);
So whatever you want to achieve, always prefer objects with automatic storage duration if the situation allows it. There's nothing worse than being forced to taking care of memory management manually and dealing with unpleasant problems such as memory leaks later.
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
You don't need to do anything.
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
You don't need to do anything.
QUESTION 2a - Is the above correct?
The code is not correct. You're violating The Rule of Three. In particular, the automatically-generated MyDynamicPoint's copy constructor and assignment operator will make a bitwise copy of the points pointer. If you copy an instance of MyDynamicPoint, you'll end up with two object sharing the same points pointer:
When one of the objects goes of scope, the other becomes unusable.
When the second object goes out of scope, its destructor will attempt to free memory that's already been freed. This is undefined behaviour.
I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
No, it does not mean that. In fact, you should probably continue to store objects by value. However, you do need to fix the rule of three.
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Since you have a list of raw pointers, the destructors will not be called automatically. The easiest way to fix that is to either store objects by value, or use std::unique_ptr or std::shared_ptr instead of raw pointers.
To question 1, there is nothing you need to do. As you store the objects by value the compiler and the library will handle everything.
However, when you store pointer as in the second case, you need to delete those pointers that you have allocated with new, or you will have a memory leak.
And you have to delete the pointers before doing the erasing, as that can invalidate the iterator:
delete *it;
myList.erase(it);
I think following should work
MyPoint* ptr = myList.back();
delete ptr;
myList.pop_back();
OR
MyPoint* ptr = myList.back();
delete ptr;
myList.erase(ptr);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
how to properly delete pointer?
i'm using std::vector to put a group of objects into it for later use, i am using DETAIL* pPtr = new DETAIL to create the pointer, and then inserting it into the vector.
the struct of DETAIL
struct DETAIL {
int nRef;
short sRandom;
};
Is this the best way to delete and erase a pointer within a vector leaving no room for memory leaks?
while(Iter1 != m_Detail.end())
{
if((*Iter1)->nRef == m_SomeVar)
{
delete *Iter1;
m_Detail.erase(Iter1);
break;
}
Iter1++;
}
Don't put raw pointers into the vector, instead use smart pointers such as std::shared_ptr. Then there is no need for delete, simply erase the pointer from vector and the pointed object will be automatically deleted.
My suggestion would be to use std::shared_ptr remove the shared pointer from the vector using erase and let it take care of deallocation. However there is nothing wrong with what you are doing but erase does not cause the vector to release the space it has allocated to hold the pointer. You can use shrik_to_fit to remove that allocated space.
i am using DETAIL* pPtr = new DETAIL to create the pointer
That's your first mistake, you're acquiring a resource (memory from the freestore and an object constructed in that memory) and not initializing an object that will take ownership and guarantee to deallocate the resources you acquired. The idiom to solve that first mistake is called Resource Acquisition Is Initialization.
It should be something like:
std::shared_ptr<DETAIL> pPtr(new DETAIL);
Or better yet:
std::shared_ptr<DETAIL> pPtr = std::make_shared<DETAIL>();
Or in C++03 replace std::shared_ptr with boost::shared_ptr (and boost::make_shared)
The next mistake is delete *Iter1; because almost any code that uses delete outside of a destructor is wrong (and all code that uses delete outside a destructor and is accompanied by a question about how to avoid memory leaks is definitely wrong.) If you use the RAII idiom you don't need to use delete because it happens automatically at the right time.
Also, why is your class called DETAIL? What's wrong with Detail instead?
I don't like answer like "never do" so I'll answer, but gives you some tricks to bypass the risk of freeing the vector without freeing the content.
if I understand well you have a vector of DETAIL pointers:
std::vector<DETAIL*> details;
So you want a method to remove and delete all pointed objects which refer to a certain m_SomeVar: (for now let's imagine it's a free function)
void free_references(int reference, std::vector<DETAIL*> & vector)
{
std::vector<DETAIL*>::iterator it = vector.begin();
while (it != vector.end())
{
if ((*it)->nRef == reference)
{
delete *it;
// erase() makes the original 'it' in an unknown state which can't be used
// erase will return a valid iterator which is, in this case, the following element
it = vector.erase(it);
}
else
{
++it;
}
}
}
As I understand in your code, the vector is member of a class. Which is good cause you'll be able to delete everything in the destructor.
However, I would use std::unique_ptr here to "give" the ownership of the pointer to the unique_ptr container inside the vector. And when the vector memory is free, the std::unique_ptr smart point make sure that the owned pointed object is freed.
I don't know if i fully understood it but have you tryied using the ZeroMemory macro?
I am storing dynamically allocated class pointers in a vector like below.
vector<Test *> v;
Test *t1 = new Test;
Test *t2 = new Test;
v.push_back(t1);
v.push_back(t2);
Now, if i have to free Test objects, i have to loop through entire vector and free one by one and then do a clear.
for(int i = 0; i<v.size(); i++)
{
delete v[i];
}
v.clear();
Is there any function in vector to free all internal objects. That function should call Test class destructor for each object.
I understand that it is difficult for Vector class whether the pointer is address of a local object or dynamically allocated.
But still, whenever developer is confident that all are dynamically allocated he could have used freeing function if provided.
Although vector is treated as advanced Array, freeing objects in an array is much easier like below.
Test *a = new Test[2];
delete []a;
Is there any function in vector to free all internal objects ?
Your examples don't do the same thing at all.
If you want the vector equivalent of this array code:
Test *a = new Test[2];
delete []a;
it is simply
std::vector<Test> a(2);
If you have a vector of pointers to dynamically allocated objects, you need to delete every one of them, as in your example:
for(int i = 0; i<v.size(); i++)
{
delete v[i];
}
but the same thing is true for an array:
Test *t1 = new Test;
Test *t2 = new Test;
Test **a = new Test*[2];
a[0] = t1;
a[1] = t2;
also has to be deleted with such a loop:
for(int i = 0; i<2; i++)
{
delete a[i];
}
delete[] a;
In the first case, you have two objects stored in a container of some sort. That container may be a vector, or it may be an array.
In both cases, because the objects are stored directly in the container, their destructors are called when the container is destroyed. You don't need to do anything to destroy or delete individual members, you just have to destroy the container (which is simpler with the stack-allocated vector, where you don't even need to call delete[])
But if your container stores pointers to dynamically allocated objects, then it is your responsibility to delete those objects at some point. And that is true whether your container is an array or a vector.
No, there is no way to request that a std::vector full of pointers automatically call delete on all of its elements.
There are, however, other, third-party containers that will make this sort of thing easier by automatically deleting pointers when they are removed from the vector, or when the vector destructs. For example, boost::ptr_vector and friends.
The short answer is no. C++ does not provide a vector of pointers free'ing function.
The long answer is twofold:
Use smart pointers, and forget about free'ing (there's shared_ptr or unique_ptr in c++0x that will serve most of your needs). Alternatively, use a Boost ptr_vector like Tyler suggested.
It's not that hard to write a simple generic algorithm to delete each item in a container (use a template with iterators).
(warning: untested code, have no time to check it)
template<class It>
void delete_clear_ptr_cont( const It &beginIt, const It &endIt )
{
for( auto it = beginIt; it != endIt; ++it )
{
delete it;
}
erase( beginIt, endIt );
}
No, vector isn't aware that it may be instantiated with pointers. And even if it was, there are situations where you don't own the pointers and you don't want the delete behavior.
In most cases we simply use a vector of smart pointers, like shared_ptr. However, there are times where shared_ptr isn't appropriate. For those cases we have a functor in our toolbox like this:
#include <functional>
template<typename T>
struct PointerDelete : public std::unary_function<T*, T*>
{
T* operator()(T*& p) const
{
delete p;
return 0;
}
};
Then, assuming you have a vector<Foo*>, you could do either:
#include <algorithm>
std::for_each(v.begin(), v.end(), PointerDelete<Foo>());
// or
std::transform(v.begin(), v.end(), v.begin(), PointerDelete<Foo>());
If you can use the boost library, there are also ptr_containers, which are containers that take ownership of pointers and do the delete for you automatically on container destruction.
I asked the same question before and I was suggested to use Boost library and you will find great tips
here or simply you can understand smart pointers as follows :
Instead of having a vector of pointers you will have a vector of smart pointers , as for each new you will make it will delete itself without you having to worry .
How does container object like vector in stl get destroyed even though they are created in heap?
EDIT
If the container holds pointers then how to destroy those pointer objects
An STL container of pointer will NOT clean up the data pointed at. It will only clean up the space holding the pointer. If you want the vector to clean up pointer data you need to use some kind of smart pointer implementation:
{
std::vector<SomeClass*> v1;
v1.push_back(new SomeClass());
std::vector<boost::shared_ptr<SomeClass> > v2;
boost::shared_ptr<SomeClass> obj(new SomeClass);
v2.push_back(obj);
}
When that scope ends both vectors will free their internal arrays. v1 will leak the SomeClass that was created since only the pointer to it is in the array. v2 will not leak any data.
If you have a vector<T*>, your code needs to delete those pointers before delete'ing the vector: otherwise, that memory is leaked.
Know that C++ doesn't do garbage collection, here is an example of why (appologies for syntax errors, it has been a while since I've written C++):
typedef vector<T*> vt;
⋮
vt *vt1 = new vt, *vt2 = new vt;
T* t = new T;
vt1.push_back(t);
vt2.push_back(t);
⋮
delete vt1;
The last line (delete vt1;) clearly should not delete the pointer it contains; after all, it's also in vt2. So it doesn't. And neither will the delete of vt2.
(If you want a vector type that deletes pointers on destroy, such a type can of course be written. Probably has been. But beware of delete'ing pointers that someone else is still holding a copy of.)
When a vector goes out of scope, the compiler issues a call to its destructor which in turn frees the allocated memory on the heap.
This is somewhat of a misnomer. A vector, as with most STL containers, consists of 2 logical parts.
the vector instance
the actual underlying array implementation
While configurable, #2 almost always lives on the heap. #1 however can live on either the stack or heap, it just depends on how it's allocated. For instance
void foo() {
vector<int> v;
v.push_back(42);
}
In this case part #1 lives on the stack.
Now how does #2 get destroyed? When a the first part of a vector is destroyed it will destroy the second part as well. This is done by deleting the underlying array inside the destructor of the vector class.
If you store pointers in STL container classes you need to manually delete them before the object gets destroyed. This can be done by looping through the whole container and deleting each item, or by using some kind of smart pointer class. However do not use auto_ptr as that just does not work with containers at all.
A good side effect of this is that you can keep multiple containers of pointers in your program but only have those objects owned by one of those containers, and you only need to clean up that one container.
The easiest way to delete the pointers would be to do:
for (ContainerType::iterator it(container.begin()); it != container.end(); ++it)
{
delete (*it);
}
Use either smart pointers inside of the vector, or use boost's ptr_vector. It will automatically free up the allocated objects inside of it. There are also maps, sets, etc.
http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/ptr_vector.html
and the main site:
http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/ptr_container.html
As with any other object in the heap, it must be destroyed manually (with delete).
To answer your first question:
There's nothing special about STL classes (I hope). They function exactly like other template classes. Thus, they are not automatically destroyed if allocated on the heap, because C++ has no garbage collection on them (unless you tell it to with some fancy autoptr business or something). If you allocate it on the stack (without new) it will most likely be managed by C++ automatically.
For your second question, here's a very simple ArrayOfTen class to demonstrate the basics of typical memory management in C++:
/* Holds ten Objects. */
class ArrayOfTen {
public:
ArrayOfTen() {
m_data = new Object[10];
}
~ArrayOfTen() {
delete[] m_data;
}
Object &operator[](int index) {
/* TODO Range checking */
return m_data[index];
}
private:
Object *m_data;
ArrayOfTen &operator=(const ArrayOfTen &) { }
};
ArrayOfTen myArray;
myArray[0] = Object("hello world"); // bleh
Basically, the ArrayOfTen class keeps an internal array of ten Object elements on the heap. When new[] is called in the constructor, space for ten Objects is allocated on the heap, and ten Objects are constructed. Simiarly, when delete[] is called in the destructor, the ten Objects are deconstructed and then the memory previously allocated is freed.
For most (all?) STL types, resizing is done behind the scenes to make sure there's enough memory set asside to fit your elements. The above class only supports arrays of ten Objects. It's basically a very limiting typedef of Object[10].
To delete the elements pointed at, I wrote a simple functor:
template<typename T>
struct Delete {
void operator()( T* p ) const { delete p; }
};
std::vector< MyType > v;
// ....
std::for_each( v.begin(), v.end(), Delete<MyType>() );
But you should fallback on shared pointers when the vector's contents are to be ... ehm... shared. Yes.
A functor that deletes pointers from STL sequence containers
The standard STL containers place a copy of the original object into the container, using the copy constructor. When the container is destroyed the destructor of each object in the container is also called to safely destroy the object.
Pointers are handled the same way.
The thing is pointers are POD data. The copy constructor for a pointer is just to copy the address and POD data has no destructor. If you want the container to manage a pointer you need to:
Use a container of smart pointers. (eg shared pointer).
Use a boost ptr container.
I prefer the pointer container:
The pointer containers are the same as the STL containers except you put pointers into them, but the container then takes ownership of the object the pointer points at and will thus deallocate the object (usually by calling delete) when the container is destroyed.
When you access members of a ptr container they are returned via reference so they behave just like a standard container for use in the standard algorithms.
int main()
{
boost::ptr_vector<int> data;
data.push_back(new int(5));
data.push_back(new int(6));
std::cout << data[0] << "\n"; // Prints 5.
std::cout << data[1] << "\n"; // Prints 6.
} // data deallocated.
// This will also de-allocate all pointers that it contains.
// by calling delete on the pointers. Therefore this will not leak.
One should also point out that smart pointers in a container is a valid alternative, unfortunately std::auto_ptr<> is not a valid choice of smart pointer for this situation.
This is because the STL containers assume that the objects they contain are copyable, unfortunately std::auto_ptr<> is not copyable in the traditional sense as it destroys the original value on copy and thus the source of the copy can not be const.
STL containers are like any other objects, if you instantiate one it is created on the stack:
std::vector<int> vec(10);
Just like any other stack variable, it only lives in the scope of the function it is defined in, and doesn't need to be manually deleted. The destructor of STL containers will call the destructor of all elements in the container.
Keeping pointers in a container is a dicey issue. Since pointers don't have destructors, I would say you would never want to put raw pointers into an STL container. Doing this in an exception safe way will be very difficult, you'd have to litter your code with try{}finally{} blocks to ensure that the contained pointers are always deallocated.
So what should you put into containers instead of raw pointers? +1 jmucchiello for bringing up boost::shared_ptr. boost::shared_ptr is safe to use in STL containers (unlike std::auto_ptr). It uses a simple reference counting mechanism, and is safe to use for data structures that don't contain cycles.
What would you need for data structures that contain cycles? In that case you probably want to graduate to garbage collection, which essentially means using a different language like Java. But that's another discussion. ;)