c++ Vector, what happens whenever it expands/reallocate on stack?
The way you construct your vector (stack or heap) doesn't matter for this.
See the documentation for std::vector
Internally, vectors use a dynamically allocated array to store their elements. This array may need to be reallocated in order to grow in size when new elements are inserted, which implies allocating a new array and moving all elements to it.
When a vector "grows", the vector object doesn't grow, only the internal dynamic array changes.
As for its implementation, you can look at GCC's vector implementation.
To keep it simple, it declares vector as a class with one protected member, of type _Vector_impl
.
As you can see, it is declared as a structure that contains three pointers :
- One that points at the beginning of the storage (and the beginning of the data)
- One that points at the end of the data
- One for the end of the storage
You wrote
[...] copy itself to a new location [...]
which is not the way a vector works. The vector data is copied to a new location, not the vector itself.
My answer should give you an idea of how a vector is designed.
The common std::vector layout*
Note: The std::allocator
is actually likely to be an empty class and std::vector
will probably not contain an instance of this class. This may not be true for an arbitrary allocator.
In most implementations it consists of three pointers where
begin
points to the start of the data memory of the vector on the heap (always on the heap if notnullptr
)end
points one memory location past the last element of the vector data ->size() == end-begin
capacity
points on memory location past the last element of the vector memory ->capacity() == capacity-begin
A vector on the stack
We declare a variable of type std::vector<T,A>
where T
is any type and A
is an allocator type for T
(i.e. std::allocator<T>
).
std::vector<T, A> vect1;
How does this look like in memory?
As we see: Nothing happens on the heap but the variable occupies the memory that is necessary for all of its members on the stack.
There it is and it will stay there until vect1
goes out of scope, since vect1
is just an object like any other object of type double
, int
or whatever. It will sit there on its stack position and wait to get destroyed, regardless of how much memory it handles itself on the heap.
The pointers of vect1
do not point anywhere, since the vector is empty.
A vector on the heap
Now we need a pointer to a vector and use some dynamic heap allocation to create the vector.
std::vector<T, A> * vp = new std::vector<T, A>;
Let's again look at the memory.
We have our vp variable on the stack and our vector is on the heap now. Again the vector itself will not move on the heap since its size is constant. Only the pointers (begin
, end
, capacity
) will move to follow the data position in memory if a reallocation takes place. Let's have a look at that.
Pushing elements to a vector
Now we can start pushing elements to a vector. Let's look at vect1
.
T a;
vect1.push_back(a);
The variable vect1
is still where it has been but memory on the heap was allocated to contain one element of T
.
What happens if we add one further element?
vect1.push_back(a);
- The space allocated on the heap for the data elements will not be enough (since it is only one memory positions, yet).
- A new memory block will be allocated for two elements
- The first element will be copied/moved to the new storage.
- The old memory will be deallocated.
We see: The new memory location is different.
To have additional insight let's look at the situation if we destroy the last element.
vect1.pop_back();
The memory allocated won't change but the last element will have its destructor called and the end pointer moves one position down.
As you can see: capacity() == capacity-begin == 2
while size() == end-begin == 1
The vector object may well be instiantiated on the stack but the data within the vector will be on the heap.
(The trivial class class foo {int* data;};
has this characteristic)