STL Container Memory Management

closed account (S6k9GNh0)
I'm a little confused. I've used containers before but I don't know (at least now I don't) that I've been using them correctly.

When I make a vector of a heavy class, I make a vector of class pointers and then assign dynamically allocated objects to the vector when needed and then iterate through and delete them when I'm done. I'm being told that the std::vector dynamically allocates the objects you use inside of the vector, even the pointers I use. I'm a little bit confused now and my head hurts (102 fever ftl) so could someone please clear this up for me.
You've been told wrong, or your understanding is wrong.

If you have a std::vector<Foo*>, the container dynamically allocates memory for pointers-to-Foo. It does not
dynamically allocate Foo objects.

(And use boost::ptr_vector<> instead, if you can. It manages the pointers for you without you having to
delete them upon removal).
closed account (S6k9GNh0)
I was under the impression ( or I wasn't until now ) that if I do: std::vector<Foo> vFoo, it automatically allocates memory for Foo on heap and removes them as well when needed.

Also, I did not know about the ptr_vector. I will definitely be using that now. Thank you.
Last edited on
I was under the impression ( or I wasn't until now ) that if I do: std::vector<Foo> vFoo, it automatically allocates memory for Foo on heap and removes them as well when needed.


Of course it does if you insert Foo objects. I don't understand what is confusing. If you have a vector of pointers then it must allocate memory to hold the pointers and if you have a vector of objects than it will need to allocate memory for whatever the object type is.
I think what he was getting at was that he was using a vector of Foo* in order to have his Foos be on the heap at all. i.e. he thought vector<Foo> didn't put Foos on the heap.
To clean up things a bit, my understanding:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
struct Foo { int i; };

// Creates 10 Foo objects in a continuous memory block on the heap. e.g. think of "new Foo[10]"
// don't call any delete on f1 or its members! It's handled everything by vector.
vector<Foo> f1(10);

// Creates 10 uninitialized pointers to Foo in a continuous memory block on the heap. You have
// to fill them before using! Use this for "heavy objects", e.g. when copying Foo is expensive
vector<Foo*> f2(10);

// Fill the previously uninitialized Foo pointers with 10 Foo objects,
// also from the heap but spread around somewhere in memory (non-continous)
for(auto i = f2.begin(); i != f2.end(); ++i) *i = new Foo;

// You have to delete the created Foo objects!
for(auto i = f2.begin(); i != f2.end(); ++i) delete *i;

// Create 10 Foo objects on the stack. there is no way to create them on the stack using vector!
// Of course, do not even think about calling delete on f3 or it's objects!
Foo f3[10];

// Old way, used in pre-vector times. Don't use this without a reason today. Use f1-way instead.
Foo* f4 = new Foo[10];

// You have to delete f4 itself (but not the objects it points to). You have to use the almost unknown delete[] for this!
delete [] f4;

// Using smart pointers to not have to worry about deletion. This is similar to f2, except you 
// must not delete the pointers yourself.
// Use this for "heavy Foo" objects, e.g. when copying/constructing Foo is expensive,
// but when you still want value-semantic of Foo (i.e. no ownership of the objects)
vector<std::tr1::shared_ptr<Foo>> f5(10);

// You still have to allocate Foo objects (but don't delete them)
// shared_ptr does not have an implicit conversion constructor..
for(auto i = f2.begin(); i != f2.end(); ++i) *i = std::tr1::shared_ptr<Foo>(new Foo);


Any corrections?

Ciao, Imi.
// Creates 10 uninitialized pointers to Foo in a continuous memory block on the heap. You have
// to fill them before using! Use this for "heavy objects", e.g. when copying Foo is expensive
vector<Foo*> f2(10);

CORRECTION: 10 pointers initialized to 0.

closed account (S6k9GNh0)
Cool... I'm guessing this is what allocator classes are for as well. It all makes sense now (and I'm missing my fever finally. Bastard was persistent.).
Last edited on
1
2
3
4
5
// Old way, used in pre-vector times. Don't use this without a reason today. Use f1-way instead.
Foo* f4 = new Foo[10];

// You have to delete f4 itself (but not the objects it points to). You have to use the almost unknown delete[] for this!
delete [] f4;


Incorrect. You still have to delete each object that is stored in the array in addition to the array itself. Presumably operator new will have been called for each object before each element of the array is assigned.

delete [] destroys the memory used to hold the array of pointers. delete is used to destroy each object and must be done before the delete[].
Last edited on
closed account (1yR4jE8b)
You are totally and completely wrong kempofighter.

For ever call to new there is ONE associated call to delete. If you allocate new Foo[10] you DO NOT have to have 10 delete foo[i] followed by one delete[] foo. This will corrupt the heap in your program.

if you allocate an array with new[], then delete it with delete[]
if you allocate an single element with new, then delete it with delete

You don't need to delete the individual elements of a new[] unless the objects are themselves pointers that point to dynamically allocated memory.

EDIT:

Sorry, you are right...I didn't realize you were talking about dynamically allocated arrays of pointers. Either way, the new/delete rules that I posted are still the correct ones.
Last edited on
Topic archived. No new replies allowed.