classes, pointers, vectors, and memory allocation

M

mosfets

Hi,

I'm having a little trouble figuring out the difference in terms of
memory allocation between:

class person_info;

class A {

private:
vector<person_info> list;
};


class B {

private:
vector<person_info*> list;
};

int func1() {

A* ptr1 = new A();
B* ptr2 = new B();

person_info info_stack;
person_info* info_heap = new person_info();
}

ptr1 and ptr2 will be dynamically allocated in the heap, but when I add
info_stack to ptr1's vector list, info_stack will be copied into the
heap??? Or will info_stack still reside in the stack? If it is added
into the heap, does A's memory get enlarged as a whole chunk? If there
is not enough space for the whole chunk, will A get copied into another
chunk in the heap big enough to fit it?
What happens when I exit func1 and info_stack gets destroyed, what will
happen to the info_stack I put into the vector in ptr1? Can I still
access it and keep using it?

When i add info_heap to ptr2's vector list, will the memory of B in the
heap be enlarged as a whole chunk?


Sorry for so many questions, but I've been really confused about this
for a while.

Thanks for any help, and for reading this!
John G
 
N

niklasb

Hi,

I'm having a little trouble figuring out the difference in terms of
memory allocation between:

class person_info;

class A {
private:
vector<person_info> list;
};

class B {
private:
vector<person_info*> list;
};

The first class contains a vector of person_info, whereas the second
contains a vector of pointer-to-person_info.
int func1()
{
A* ptr1 = new A();
B* ptr2 = new B();

person_info info_stack;
person_info* info_heap = new person_info();
}

ptr1 and ptr2 will be dynamically allocated in the heap, but when I add
info_stack to ptr1's vector list, info_stack will be copied into the
heap???

Standard containers like vector are value-oriented, meaning they
store copies of whatever objects you add to them. So yes, info_stack
will be copied to wherever the vector stores its contents, which is
probably a chunk of memory allocated on the 'heap' (called the
'free store' by the C++ standard).
Or will info_stack still reside in the stack?

info_stack still exists on the 'stack' ('free store' in standardese)
and will continue to do so until it passes out of scope. The vector
ptr1->list contains a separate person_info object which was created
by copying info_stack. These are now two separate objects.
If it is added
into the heap, does A's memory get enlarged as a whole chunk? If there
is not enough space for the whole chunk, will A get copied into another
chunk in the heap big enough to fit it?

The size of A doesn't change over time. In fact, sizeof(A) is a
constant known at compile time. However, many objects allocate memory
dynamically (from the free store, aka., heap). For example, a vector
typically contains a pointer to a memory buffer that contains the
elements of the vector. The vector allocates the memory, manages it,
and eventually frees it. All that memory management is part of the
internal implementation of vector and is hidden from you.
What happens when I exit func1 and info_stack gets destroyed, what will
happen to the info_stack I put into the vector in ptr1? Can I still
access it and keep using it?

Yes, the vector stores a copy, not the object itself.
When i add info_heap to ptr2's vector list, will the memory of B in the
heap be enlarged as a whole chunk?

Same as above, sizeof(vector) doesn't change, but the total memory
used by a vector might change over time because the vector can
allocate memory from the free store.

As to the difference between the two vectors, the key to understanding
a vector of pointers (or pointers generally) is that the pointer and
the thing it points to (the pointee) are two distinct objects. Let me
explain with another example:

void f()
{
int n = 1;
int* p = new int(2);

// There are now two objects on the 'stack' (n and p) and one
object
// on the 'heap' (the integer p points to).

vector<int> v;
v.push_back(n);
v.push_back(*p);

// We now have a third object on the 'stack' (v), which is a
// vector containing two objects of type int. Vectors and other
// standard containers are value-oriented, meaning they store
// *copies* of the objects you add to them. Thus, we now have a
// total of four integers, n, *p, v[0], and v[1]. Where are the
// last two integers? Wherever the vector decides to put them.
// Most likely, it will have allocated some memory on the 'heap',
// but the point is it's the vector's job to manage that memory
// (including freeing it when the vector itself is destroyed)
// so you don't need to care.

vector<int*> w;
w.push_back(p);
w.push_back(&n);

// The fourth object on the 'stack' (w) is also a vector, and it
// two contains two objects, in this case of type pointer-to-int.
// A key to understanding pointers in C++ is that a pointer is an
// object in its own right, distinct from the thing it points to
// (the 'pointee'). We've added two pointers to w (p and the
// address of n) and it has stored copies of them. It 'owns' those
// copies and is responsible for eventually freeing them -- just
// like the vector of ints -- but it's important to understand
// that w's ownership only extends to the pointers themselves, not
// to the objects they point to.
//
// That's why, when you have a vector of pointers, it is up to
// *you* to manage the lifetime of whatever objects those pointers
// point to. The vector only 'owns' the pointers themselves; and a
// raw pointer (unlike some 'smart pointer' classes) doesn't 'own'
// anything.
//
// Since you asked about memory layout, here's a diagram of what
// our program might look like so far:
//
// 'stack' 'heap'
//
// +-------+
// n | 1 | <-----------------------+
// +-------+ |
// +-------+ +-------+ |
// p | * ---------> | 2 | <--+ |
// +-------+ +-------+ | |
// +-------+ | |
// v | ... | +-------+ | |
// | * ---------> | 1 | | |
// | ... | +-------+ | |
// +-------+ | 2 | | |
// +-------+ +-------+ | |
// w | ... | +-------+ | |
// | * ---------> | * -------+ |
// | ... | +-------+ |
// +-------+ | * -----------+
// +-------+
//
// From the preceding discussion, it should be clear that we (not
// the vector w) are responsibe for eventually deleting the object
// we earlier allocated using new. So here we go:

delete p;

// How should one describe the statement above? Many people would
// say we just 'deleted the pointer p.' That's fine as long as you
// understand that it's not precisely true. What we've actually
// deleted is the pointee, the integer p pointed to. The pointer
// object itself (i.e., p) still exists, although now it holds
// an invalid pointer value, which means we're not allowed to do
// anything with it except assign to it.

p = &n; // p still exists; let's assign to it just to show we can
p = NULL; // another equally useless assignment
}
 
M

mosfets

Thanks for the nice detailed reply! It helped alot in my understanding
:)

Regards,
John G
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top