Notes

Thoughts, write-ups, and things worth remembering.

std::vector

#cpp#containers Updated Sep 16, 2026

A dynamically resizeable array. The default container to reach for when unsure what you need.

std::vector<int> v;
v.push_back(5);       // add to the end
v.push_back(10);
v[0];                  // 5, no bounds check
v.at(0);               // 5, throws if out of range
v.size();              // 2
for (int x : v) { ... }  // range-based iteration

Under the hood

Backed by a contiguous heap array, like a C-array, but it tracks its own size and grows itself. When it outgrows its current allocation, it allocates a bigger block, copies (or moves) everything over, and frees the old one.

push_back vs emplace_back

Node obj(1.0f, 2.0f);   // construct the object first...
v.push_back(obj);        // ...then copy (or move, if obj is an rvalue) it in

v.emplace_back(1.0f, 2.0f);   // constructs the Node directly inside the vector's
                                // storage - no separate object, no copy/move at all

push_back needs a fully-formed object handed to it — building one always costs a construction, then a copy or move into place. emplace_back forwards its arguments straight to the object’s constructor, building it in-place in the vector’s already-allocated memory.

For a cheap type (an int), the difference is noise. For an expensive-to-copy/move type, skipping that extra step is a real, measurable win — the same spirit as move semantics, just automated one step further.

Gotcha: emplace_back isn’t automatically faster

Node existing = getNode();
v.push_back(std::move(existing));   // one move, cheap if Node has a move ctor
v.emplace_back(existing);            // re-runs the FULL constructor from scratch -
                                       // might be more work than a move

Already have a constructed, move-friendly object? push_back(std::move(...)) can beat emplace_back — emplace only wins when building the object fresh from its constructor arguments.

Gotcha: reallocation invalidates pointers/iterators

int* p = &v[0];
v.push_back(100);   // might reallocate!
*p;                  // p may now be dangling - UB

Never hold a raw pointer/iterator into a vector across a push_back/insert/erase unless you’re certain no reallocation happened.

C-style arrays
std::string