1
votes

From my understanding so far, if you have a vector of class objects, if you erase any member of the vector, typically the vector will reallocate some of it's objects in order to preserve memory contiguousness. Hence you need to implement the rule of three (destructor, copy constructor and copy assignment operator) for everything to be preserved when erasing vector members.

However: for a vector of pointers to class objects the outcome is less clear to me. If I erase a member, then surely C++ is smart enough to just copy the pointers around - not maddeningly delete the pointer (and the class object it points to) then re-create it and the object it points to again?

If this is not the case, can someone explain this idiocy to me?

2

2 Answers

1
votes

The vector will leave your pointer values alone. It of course will move the values in the internal array when you push, pop, or erase.

In this case the values are just pointers. But there is no logic in the vector to determine if something is a pointer to an object and delete/reallocate them when the values are copied.

In the case of a vector that includes a complex type and not a pointer it will of course try to copy the values when the internal array is reallocated or moved.

1
votes

The vector will delete, construct, and copy whatever type it contains. In the case of a vector of pointers to a class/structure, it will delete, construct, and copy pointers, leaving the actual objects the pointers point to alone. It is up to you to allocate and deallocate these.


EDIT

An example:

If you have the following:

class A
{
  A() {}
}

void foo(void)
{
   A * pointerToA = new A;
}

At the end of the function foo's scope the only thing that is deallocated is the memory for the variable pointerToA itself, i.e. 4 bytes that hold an address (in 32 bit) - which in this case is stored on the stack. The only way that the memory allocated for a new instance of class A will be freed is if you manually call delete with the address to pointerToA.

Let's take the example of an array of class A

A ** arrayOfPointerToA = new A*[10];
for(unsigned i = 0; i < 10; ++i)
  arrayOfPointerToA[i] = new A;

which is similar to what happens when you have std::vector<A*>. When you call

delete [] arrayOfPointerToA;

you're deallocating the memory for the array of pointers, not for each A.

enter image description here

In the above diagram, the memory deallocated by the above call to delete is highlighted in red. Note that each A is stored at a random location in memory in this instance since they were all allocated separately.

Now taking this to a vector:

A std::vector<A> effectively uses new A[size] to allocate memory. If you're storing a raw pointer, this would mean it would allocate an array of type A, which means that size number of objects of type A are created. When the vector frees its memory size number of objects of type A are destroyed. Now take that example and replace A with A* and you'll see that no objects of type A are destroyed.

This is a fundamental part of how C++ and pointers work, not just a property of containers. If containers did arbitrarily call delete on each member, this wouldn't make sense as when we have a container A we would call delete on an instance of an object instead of a pointer to that object which is not valid.