38 Intermediate The Hundred
reserve Is Not resize
the score you wrote down, and then couldn't find
#include <iostream>
#include <vector>
int main() {
std::vector<int> scores;
scores.reserve(5); // make room for five scores
std::cout << "size " << scores.size() << ", capacity " << scores.capacity() << "\n";
scores[0] = 42; // record the first score
std::cout << "stored " << scores[0] << ", size " << scores.size() << "\n";
scores.push_back(7); // and now the second one
std::cout << "scores[0] is " << scores[0] << ", size " << scores.size() << "\n";
}
Run it. Where does 42 end up?
Answer
Nowhere. Typical output (GCC on x86-64), identical at -O0 through -O3:
The vector hands back 42 while still reporting a size of 0 — and then loses it.
Why¶
reserve(5) buys space, not elements: it allocates a buffer for five ints and leaves
size() at 0. So scores[0] indexes past the last element — there is no element zero —
and the write is undefined behavior. It appears to work because the storage really is
there and nobody else is using it yet, so the read hands back your 42. Then push_back(7)
constructs at index size(), still 0, and stamps 7 right on top — the vector never knew
about your value. scores.at(0) would have thrown: the checked accessor asks about size.
Nothing warns by default — not -Wall -Wextra, nor stock -fsanitize=address on libstdc++.
-D_GLIBCXX_ASSERTIONS aborts (Assertion '__n < this->size()' failed), and ASan does flag
it as a container-overflow once vector annotations are on (-D_GLIBCXX_SANITIZE_VECTOR).
The fix¶
Use resize when you want elements, reserve when you only want to avoid reallocation:
scores.resize(5); // five real elements, value-initialized to 0
scores[0] = 42; // legal — element 0 exists
std::vector<int> other;
other.reserve(5); // still empty: you must grow it, you may not index it
other.push_back(42); // one of five that fit without reallocating
Takeaway: capacity is room, size is elements — indexing is only valid below size().
Try it: g++ -std=c++17 main.cpp -o demo && ./demo