A C++ vector looks like an array, but it can grow, owns its storage and may invalidate an iterator when it changes. That combination is useful, and it is where beginner mistakes come from: vector<int> v(5) and vector<int> v{5} are different vectors, reserve(100) does not make v[99] legal, and an iterator saved across a push_back can dangle. In C++, vector means std::vector from <vector>, not a mathematical vector or a C array.
What a vector is in C++
std::vector<T> is a standard-library sequence container. It stores elements of one type in contiguous order and manages its storage as elements are added or removed. Its size() is the number of live elements. Its capacity() is how many elements can fit before more storage is needed. The capacity growth factor is implementation-dependent, so code must not assume one.
The minimum declaration is:
#include <vector>
std::vector<int> scores;Construction syntax matters:
Construction | Elements | Size |
|---|---|---|
|
| 0 |
|
| 3 |
|
| 3 |
|
| 2 |
Parentheses can request a count and an initial value. Braces list explicit elements, which is the whole of the (3) versus {3,9} difference above. More C++ walkthroughs sit under Programming Languages.
Access and traverse vector elements safely
Start with std::vector<int> values{12, 5, 19, 8}. Then values[0], values.front(), values.back() and values.size() give 12, 12, 8 and 4. After values[2] = 20, the vector is {12,5,20,8}.
int sum = 0;
for (int x : values) {
std::cout << x << ' '; // 12 5 20 8
sum += x;
}
std::cout << "\nsum = " << sum; // 45Both values[2] and values.at(2) read 20. However, values.at(4) throws std::out_of_range, while values[4] is unchecked and must not be used. For a runtime index i, test if (i < values.size()) first. Test !values.empty() before calling front() or back().
A range loop copies each element unless its variable is a reference:
std::vector<int> nums{6,13,21,9};
for (int x : nums) { x += 1; } // nums is unchanged
for (int& x : nums) { x += 1; } // nums is {7,14,22,10}Use const int& for read-only iteration when copying a larger element type would be wasteful.
Worked vector example: build, insert, erase, sort and total
This complete program uses direct operations and plain loops, so every state and total remains visible.
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> scores{18, 7, 25, 11};
scores.push_back(30);
scores.insert(scores.begin() + 2, 14);
scores.erase(scores.begin() + 1);
std::sort(scores.begin(), scores.end());
int sum = 0;
for (int x : scores) {
std::cout << x << ' ';
sum += x;
}
int atLeast18 = 0;
for (int x : scores) {
if (x >= 18) ++atLeast18;
}
std::cout << "\nsum = " << sum;
std::cout << "\nvalues >= 18 = " << atLeast18 << '\n';
}Trace it operation by operation:
Step | Vector | Size |
|---|---|---|
Start |
| 4 |
|
| 5 |
Insert |
| 6 |
Erase index 1 |
| 5 |
Sort |
| 5 |
The program prints 11 14 18 25 30. Its sum is 11 + 14 + 18 + 25 + 30 = 98. Three values, 18, 25 and 30, are at least 18. With floating-point division, the mean is 98 / 5 = 19.6. The C++ Programming course carries the same push_back, insert, erase and sort vocabulary through the rest of the standard library.

Iterators, positions and mutation rules
begin() points to the first element. end() is a one-past-the-last sentinel, not an element to dereference. With std::vector<int> readings{6,13,21,9}, advance while the iterator is not end() and *it < 20. It stops at 21, and it - readings.begin() gives index 2.
In the worked program, scores.begin() + 2 identifies index 2. insert places the new element before that position. erase removes the element at its iterator and returns an iterator to the next surviving element. That return value enables safe removal during traversal:
std::vector<int> mixed{4,-2,7,-1};
for (auto it = mixed.begin(); it != mixed.end(); ) {
if (*it < 0) it = mixed.erase(it);
else ++it;
}
// mixed is {4,7}A reallocation invalidates all vector iterators, pointers and references. An erase invalidates those at or after its position. An insertion without reallocation still invalidates those at or after its insertion point. The practical rule is to reacquire iterators after push_back, insert, erase, reserve or resize instead of carrying one across the mutation.
Size, capacity, reserve and resize are different
For std::vector<int> v{4,6}, size is 2 and capacity is at least 2. After v.reserve(5), the elements remain {4,6}, size stays 2 and capacity is at least 5. Indexes 2, 3 and 4 still do not identify elements.
Next, v.resize(5) produces {4,6,0,0,0} with size 5 because the three new int elements are value-initialised. Then v.resize(1) leaves {4} with size 1; capacity is not required to shrink. Use reserve to reduce reallocations when an approximate final count is known. It reserves storage but creates no elements.

Complexity choices and common vector mistakes
Vector's cost model is what decides whether it is the right container:
Operation | Complexity |
|---|---|
Indexed access, |
|
| Amortised |
Insert or erase near the middle |
|
Linear search |
|
|
|
Amortised means the average cost across many appends, not a guarantee for each append. A vector is a strong default for ordered contiguous storage, indexed reads and growth at the end. It is a poor fit when repeated front or middle insertions and deletions dominate. Read DSA & Algorithms for side-by-side container comparisons and the algorithms that run over them.
Repair these common mistakes:
vector<int> v{5}is{5}, whilevector<int> v(5)is five zeros.Use
i < v.size(), noti <= v.size(), in an indexed loop.reserve(100)does not permitv[99]; useresizeorpush_back.Do not use a saved iterator after a mutation that invalidates it.
Pass
const std::vector<int>& vfor read-only input when no copy is intended.
Three exact vector exercises
Solve these on paper before running anything. Each one targets a place where vector code usually breaks: the index arithmetic of insert and erase, the running total of a traversal, and the split between reserved storage and live elements.
Start with
{3,8,2}, callpush_back(5), insert7atbegin()+1, then erasebegin()+3. Find the final vector and size.For
{9,4,12,4,7}, calculate the sum and count values greater than6.Start with
{2,5}and callreserve(6). What size and elements are guaranteed? Then callresize(6,9). What changes?
Check only after solving: Exercise 1 gives {3,7,8,5}, size 4. Exercise 2 gives sum 9 + 4 + 12 + 4 + 7 = 36, with three values greater than 6. Exercise 3 remains size 2 with {2,5} after reserve, then becomes size 6 with {2,5,9,9,9,9} after resize.
For the same kind of practice across more languages, Coding For Placements covers C, C++, Java, Python and competitive coding.
Vector in C++, the short version and next step
Keep six rules: use braces for explicit elements; use push_back to append; check empty() and indexes before access; remember that reserve changes storage while resize changes element count; reacquire iterators after invalidating mutations; choose a vector when indexed access and end growth dominate. In the worked trace, {18,7,25,11} becomes {11,14,18,25,30} after the append, insert, erase and sort sequence.
Now run the program, change inserted 14 to 16, and recompute. The sorted vector becomes {11,16,18,25,30}, the sum is 100, and the count at least 18 remains 3. Then solve the three exercises without looking at the checks. Continue with the C++ Programming course for the full language sequence or browse Coding & DSA for the broader category.




