Reputation: 165
Consider the following example:
#include <vector>
class Foo {
std::vector<int*> v;
public:
Foo() {
this->v.push_back(new int(23));
this->v.push_back(new int(24));
this->v.push_back(new int(25));
}
~Foo() {
}
};
int main() {
Foo f;
return 0;
}
When f goes out of scope in main(), f's destructor is called, which should indirectly free f.v. According to this, the destructor of each element of the vector v should now be called.
However, when I run this program in valgrind, I find that the int*'s were not deallocated.
$ valgrind --leak-check=full ./a.out
What am I missing here?
Upvotes: 2
Views: 3131
Reputation: 15099
Since you are using the new
keyword, the integers are being allocated on the heap rather than the stack. In other words, they are being allocated dynamically. In other words, you need to clean up after it.
The "destructor" for a pointer type is to simply delete that pointer. It does not touch the data which is located at the memory address stored by the pointer. Consider the following example:
int a = 5;
int* i = &a;
if (true)
{
int* j = i;
} //j goes out of scope, should *i and a be deleted? no.
So you will need to do this in the destructor:
std::vector<int*>::iterator iter;
for (iter = v.begin(); iter != v.end(); iter++)
{
delete *iter;
}
Upvotes: 2
Reputation: 231113
std::vector<T>
does indeed call the destructor of T
when it is destroyed. Here T
is int *
. The destructor of int *
does nothing. The storage for the int *
itself is freed, but the int
s they point to are not.
Consider:
int main() {
int *x = new int(23);
return 0;
}
This exhibits the same problem; when x
goes out of scope, its destructor is indeed called, and the storage for the pointer that is x
is freed, but since the destructor of a pointer is a no-op, the pointed-to int
is not freed.
More to the point, vector
doesn't know how the int
s were allocated. They might be allocated by new int
, but they could also point to elements inside an array allocated with new int[200]
, or they might point to malloc
'd data, or they might point into a mmap
'd buffer, or they might point to struct elements, or two vectors might be pointing to the same int
s... etc. vector
isn't smart enough to divine what you want done with these, and so it leaves them alone (additionally, giving vector
logic to delete pointed-to elements would break vectors of non-pointer elements such as std::vector<int>
, as you can't delete
an int
!)
You need to either use a std::vector<int>
, or use a smart pointer in conjunction with it, eg std::vector<boost::shared_ptr<int> >
. Note that using smart pointers may add overhead; with C++0x you should be able to use std::vector<std::unique_ptr<int>>
in conjunction with std::move
to avoid this overhead. Boost also has pointer vectors that free the pointed-to elements as you expected as well.
Upvotes: 10
Reputation: 272487
Each element of your vector is an int *
. When an int *
is destroyed, the language does not automatically call delete
on it. In other words, it's the pointer being destroyed, not the pointee.
Upvotes: 2
Reputation: 355049
The destructor of each element of the vector
v
should now be called
Yes: the int*
objects stored in the vector are destroyed (which is effectively a no-op). The objects pointed to by the pointers in the container are not destroyed.
Consider the following, equally valid program:
{
int x;
std::vector<int*> v;
v.push_back(&x);
} // x cannot be delete'd because it isn't dynamically allocated.
You should use a smart pointer, like std::unique_ptr
or shared_ptr
so that you don't have to worry about the memory management (do not use std::auto_ptr
; it is incompatible with the Standard Library containers because it isn't really copyable). If you don't use a smart pointer then you need to destroy the dynamically objects yourself; doing this correctly is rather difficult.
Upvotes: 4