stack · main()heap (free store)datasizecapacityint* p0x5a100x5a140x5a300x5a340x5a380x5a3c1#include <iostream>2#include <vector>3int main() {4 std::vector<int> v;5 v.reserve(2);6 v.push_back(10);7 v.push_back(20);8 v.push_back(30);9 for (int x : v)10 std::cout << x << ' ';11}!reserve(2)0x5a101020new block1020300x5a30102030~vector
Violet card: the program (grow.cpp); a highlighted line is the one runningBlue cells: the vector object v on the stack; khaki cells: int slots on the heap (faint = not reserved)Arrow: where data points (red = a dangling pointer); tokens: calls, addresses and values on the moveIn front: the source card grow.cpp and the output block. At the back: main's stack frame with the vector object v (data, size, capacity), and the heap with a block of 2 ints and a block of 4 ints. push_back is quick while there is spare capacity. When the block is full the vector gets a bigger block, copies the elements across and frees the old one, so old pointers into it dangle (red). At the closing brace the vector's destructor frees its block: no delete needed. The addresses 0x5a10 and 0x5a30 are made up and short so they fit. Real ones are longer, change from run to run, and the new block need not sit right after the old one.

An empty vector

  1. std::vector<int> v; makes an empty vector, the standard library's go-to container. The object v lives on the stack and holds three things: where its elements are (data), how many it has (size) and how many fit (capacity).

Filling it

Growing

Using and freeing

What happens

;; step 1/10 · vector
4  std::vector<int> v;
   v on the stack:  data = nullptr   size = 0   capacity = 0
   no elements yet, so no heap memory yet
   sizeof(v) = 24 bytes with libstdc++ or libc++ on 64-bit, however many elements
   the elements will live on the heap, side by side

The C++ standard does not fix how much a vector grows, only that push_back takes amortised constant time. GCC's libstdc++ and LLVM's libc++ double the capacity (2 becomes 4); Microsoft's STL grows by half (2 becomes 3). reserve(2) gives a capacity of at least 2; all three give exactly 2. The addresses 0x5a10 and 0x5a30 are made up and short so they fit. Real ones are longer, change from run to run, and the new block need not sit right after the old one.