Vectors

std::vector is the container you'll use most. It's a dynamic array: elements are stored contiguously like an array, but it grows as you add them and frees its memory automatically. When you don't know which container to pick, pick a vector.

Creating and adding

C++
#include <iostream>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> tasks;                // empty
    tasks.push_back("write report");
    tasks.push_back("email Sam");
    tasks.emplace_back("book train");              // constructs the string in place

    std::vector<int> numbers{5, 3, 8};             // from a list
    std::vector<double> zeros(4);                  // four 0.0 values
    std::vector<char> dashes(10, '-');             // ten '-' characters

    std::cout << tasks.size() << " tasks, first: " << tasks.front() << ", last: " << tasks.back() << '\n';
    std::cout << numbers.size() << ' ' << zeros.size() << ' ' << std::string(dashes.begin(), dashes.end()) << '\n';
}
Output
3 tasks, first: write report, last: book train
3 4 ----------

Note the difference: std::vector<int>{4} is one element with value 4, but std::vector<int>(4) is four zeros. Braces mean "these elements"; parentheses call a sizing constructor.

Accessing elements

C++
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v{10, 20, 30, 40};
    v[1] = 25;                 // unchecked
    v.at(2) = 35;              // checked: throws std::out_of_range if invalid
    for (std::size_t i = 0; i < v.size(); ++i) std::cout << i << ':' << v[i] << ' ';
    std::cout << '\n' << std::boolalpha << v.empty() << '\n';
}
Output
0:10 1:25 2:35 3:40
false

Removing elements

C++
#include <algorithm>
#include <iostream>
#include <vector>

void print(const std::vector<int>& v) {
    for (int x : v) std::cout << x << ' ';
    std::cout << '\n';
}

int main() {
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8};
    v.pop_back();                          // remove the last
    print(v);
    v.erase(v.begin() + 1);                // remove the element at index 1
    print(v);
    v.insert(v.begin(), 0);                // insert at the front
    print(v);
    std::erase_if(v, [](int x) { return x % 2 == 0; });   // remove all even numbers (C++20)
    print(v);
    v.clear();
    std::cout << "size after clear: " << v.size() << '\n';
}
Output
1 2 3 4 5 6 7
1 3 4 5 6 7
0 1 3 4 5 6 7
1 3 5 7
size after clear: 0

Adding or removing at the end is fast. Inserting or erasing near the front shifts every later element, so it's slow for big vectors. [](int x) { … } is a lambda — a small inline function (lesson 24).

Size and capacity

A vector allocates spare room (its capacity) so that most push_back calls don't need a new allocation. When it runs out, it allocates a bigger block (typically 1.5–2× larger) and moves the elements across:

C++
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v;
    std::size_t last_capacity = 0;
    for (int i = 0; i < 100; ++i) {
        v.push_back(i);
        if (v.capacity() != last_capacity) {
            last_capacity = v.capacity();
            std::cout << "size " << v.size() << " -> capacity " << last_capacity << '\n';
        }
    }
}
Output
size 1 -> capacity 1
size 2 -> capacity 2
size 3 -> capacity 4
size 5 -> capacity 8
size 9 -> capacity 16
size 17 -> capacity 32
size 33 -> capacity 64
size 65 -> capacity 128

The growth pattern differs between standard libraries (this is libc++). If you know roughly how many elements you'll add, v.reserve(n) allocates once up front.

Invalidation: when a vector reallocates, all pointers, references and iterators to its elements become invalid. Don't hold on to &v[0] while you push_back — use indexes, or reserve enough space first.

Vectors of structs

C++
#include <iostream>
#include <string>
#include <vector>

struct Product {
    std::string name;
    double price;
    int stock;
};

int main() {
    std::vector<Product> inventory{
        {"Notebook", 3.50, 40},
        {"Pen", 1.20, 150},
    };
    inventory.push_back({"Backpack", 39.90, 6});
    double value = 0;
    for (const auto& p : inventory) value += p.price * p.stock;
    std::cout << inventory.size() << " products, stock value " << value << '\n';
}
Output
3 products, stock value 559.4

2D vectors

C++
#include <iostream>
#include <vector>

int main() {
    int rows = 3, cols = 4;
    std::vector<std::vector<int>> grid(rows, std::vector<int>(cols, 0));
    grid[1][2] = 7;
    for (const auto& row : grid) {
        for (int cell : row) std::cout << cell << ' ';
        std::cout << '\n';
    }
}
Output
0 0 0 0
0 0 7 0
0 0 0 0

Try it yourself

Read numbers until the input ends, store them in a vector, and print how many there were, their average and the values above the average.

Try it yourself · main.cpp
Edit the code, copy it into main.cpp, then compile and run it with c++ -std=c++20 -Wall main.cpp -o main && ./main. How to set up a C++ compiler
Input
4 8 15 16 23 42
Output
6 values, average 18
above average: 23 42