std::vector is the most-used container in C++; it is the right default for almost any list of things.
C++ inherited built-in arrays from C: int a[3] = {1, 2, 3};. Their size is fixed at compile time, they don't know their own size when passed to a function (they decay to a pointer), they can't be assigned, and a[10] is not checked. Modern code rarely uses them directly.
std::array<int, 3> (header <array>) is a fixed-size array with no overhead that behaves like a proper value: it knows its size(), can be copied and compared, and works with the standard algorithms.
std::vector<T> (header <vector>) is a dynamic array: elements sit contiguously in heap memory and the vector grows as needed.
push_back(x)appends;emplace_back(args...)constructs the element in place;pop_back()removes the last one.size(),empty(),front(),back(),clear().v[i]is unchecked (out of range is undefined behaviour);v.at(i)checks and throwsstd::out_of_range.reserve(n)preallocates capacity when you know roughly how many elements are coming, avoiding repeated reallocations.
When a vector runs out of capacity it allocates a bigger block (typically 1.5x or 2x), moves the elements over and frees the old block. Appends are therefore cheap on average, but any pointers, references or iterators to elements become invalid after a reallocation. Don't hold on to &v[0] across a push_back.
Contiguous storage is why std::vector is so fast: iteration is cache-friendly and the CPU prefetches well. Even when you insert in the middle now and then, a vector usually beats a linked list. Make it your default container.
Example
#include <array>
#include <iostream>
#include <stdexcept>
#include <vector>
int main() {
int raw[3] = {1, 2, 3}; // C array: fixed, unchecked
std::array<int, 3> fixed{4, 5, 6}; // fixed size, knows its size, copyable
std::vector<int> v; // dynamic array on the heap
v.reserve(10); // optional: preallocate
for (int i = 0; i < 5; ++i) v.push_back(i * i); // 0 1 4 9 16
v.pop_back(); // removes 16
std::cout << v.size() << ' ' << v.front() << ' ' << v.back() << '\n'; // 4 0 9
std::cout << v[1] << '\n'; // 1, unchecked access
try {
std::cout << v.at(10) << '\n'; // checked
} catch (const std::out_of_range&) {
std::cout << "out of range\n";
}
std::cout << raw[0] + fixed[2] << ' ' << fixed.size() << '\n'; // 7 3
std::vector<std::vector<int>> grid(2, std::vector<int>(3, 0)); // 2 x 3 zeros
grid[1][2] = 7;
}Remember
std::vectoris the default container: contiguous, fast, growablev[i]is unchecked,v.at(i)throws on a bad index- Growth reallocates and invalidates pointers, references and iterators to elements
Watch out for
- Keeping a reference or pointer to an element and then calling
push_back, which may reallocate and leave it dangling.