What you'll learn
Quick Answer
A C++ vector (std::vector) is a dynamic array from the Standard Template Library that grows and shrinks while your program runs, so you never manage the memory by hand. You add items with push_back, read them with v[i] or the bounds-checked v.at(i), and loop over them with a range-based for. For almost all everyday C++ code, prefer a vector over a raw array.
What is a C++ vector?
A C++ vector (std::vector) is a resizable array from the Standard Template Library (STL). A plain array in C++ has a fixed size that you decide at compile time — once you write int marks[30]; you are stuck with 30 slots. A vector removes that limit: it grows and shrinks while your program runs, and it looks after the memory for you.
Think of it as a smarter array. You still get fast index access (v[i]), your data still sits in one continuous block of memory, but you also get handy methods like push_back(), size(), and automatic clean-up. For beginners this means fewer crashes and no manual new/delete.
To use it, include the header and, optionally, pull in the std namespace:
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<int> marks; // an empty vector of ints
marks.push_back(90);
cout << marks.size() << "\n"; // 1
}
How to declare a vector
The type inside the angle brackets is the type of element the vector holds. vector<int> stores ints, vector<string> stores strings, and so on. Here are the common ways to create one:
vector<int> a; // empty, size 0
vector<int> b(5); // 5 ints, each set to 0
vector<int> c(5, 42); // 5 ints, each set to 42
vector<int> d = {1, 2, 3}; // list of values
vector<int> e(d); // a copy of dThe pattern vector<int> c(5, 42) is worth remembering: the first number is the count, the second is the value to fill with. Mixing these up is a common early mistake, so read it as "five copies of forty-two".
Adding elements with push_back
push_back() adds one element to the end of the vector and makes it one longer. This is the everyday way to fill a vector when you do not know the size ahead of time — for example, reading numbers until the input ends.
vector<int> marks;
marks.push_back(90);
marks.push_back(85);
marks.push_back(78);
// marks is now {90, 85, 78}, size 3A few related methods you will use often:
pop_back()— removes the last element.back()andfront()— read the last / first element.emplace_back()— like push_back but builds the element in place; handy for objects.clear()— removes everything, leaving size 0.
Accessing elements: [] vs at()
There are two ways to read or write an element by position. Both use zero-based indexing, so the first element is index 0.
vector<int> v = {10, 20, 30};
cout << v[1] << "\n"; // 20 — square brackets
cout << v.at(1) << "\n"; // 20 — at()
v[0] = 99; // writing works tooThe difference is bounds checking. v.at(5) on a 3-element vector throws a std::out_of_range exception that you can catch. v[5] does no checking at all — it is undefined behaviour, which may crash, may print garbage, or may seem to "work" while quietly corrupting data.
Rule of thumb: use[]in tight loops where you have already checked the range, andat()when the index comes from user input or you want a clear error instead of a silent bug.
Size vs capacity
These two look similar but mean different things, and confusing them trips up many learners.
size()— how many elements are actually stored right now.capacity()— how many elements the vector can hold before it must grab more memory.
A vector keeps a block of memory that is often bigger than it currently needs. When you push_back and there is no room left, it allocates a larger block (commonly about double the size) and copies the old elements over. That is why capacity() tends to grow in jumps like 1, 2, 4, 8, 16.
vector<int> v;
for (int i = 0; i < 5; i++) {
v.push_back(i);
cout << "size=" << v.size()
<< " capacity=" << v.capacity() << "\n";
}If you know roughly how many items you will add, call v.reserve(1000) first. This sets the capacity up front and avoids repeated re-allocations, which makes the loop faster. Note that reserve changes capacity, not size.
Looping over a vector
The cleanest way to visit every element is the range-based for loop:
vector<int> v = {1, 2, 3, 4};
for (int x : v)
cout << x << " "; // 1 2 3 4Here x is a copy of each element. To change the elements in place, take a reference with &. To read large objects without copying, use const auto&:
for (int &x : v) x *= 2; // doubles each element
for (const auto &x : v) cout << x; // read-only, no copyWhen you need the index, loop with a counter. Use size_t to match the type that size() returns:
for (size_t i = 0; i < v.size(); i++)
cout << i << ": " << v[i] << "\n";The classic low-level option is iterators, which many STL algorithms expect:
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << " "; // *it reads the element
2D vectors (a grid)
A 2D vector is simply a vector whose elements are themselves vectors — perfect for grids, matrices, and game boards. The type is vector<vector<int>>.
// 3 rows, 4 columns, every cell 0
vector<vector<int>> grid(3, vector<int>(4, 0));
grid[0][0] = 5;
grid[1][2] = 9;
for (const auto &row : grid) {
for (int val : row)
cout << val << " ";
cout << "\n";
}Read the constructor as "3 copies of a row, where each row is 4 zeros". Unlike a fixed 2D array, each row can even be a different length (a "jagged" grid) if you build it with push_back. For most competitive-programming and matrix tasks, this one line replaces a lot of manual memory work.
Vector vs raw array
Raw arrays still have their place — small, fixed, performance-critical buffers — but for everyday code the vector wins on safety and convenience.
| Feature | std::vector | Raw array |
| Resizes at runtime | Yes | No |
| Knows its own size | Yes | No |
| Bounds-checked access | With at() | No |
| Manages its own memory | Yes | No |
| Works cleanly with STL algorithms | Yes | Partial |
| Zero overhead | Almost | Yes |
The recommendation is simple: reach for std::vector by default, and only drop down to a raw array when you have a measured reason. If you want a guided path from the basics through STL containers like this, our free C++ course walks through it step by step.
Frequently Asked Questions
What is the difference between a C++ vector and an array?
A raw array has a fixed size set at compile time and does not know its own length. A std::vector is a dynamic array that resizes at runtime, tracks its length with size(), manages its own memory, and offers helpers like push_back() and at(). For most code, prefer a vector.
Is v[i] or v.at(i) faster in C++?
v[i] is slightly faster because it skips bounds checking, while v.at(i) checks the index and throws std::out_of_range if it is invalid. In hot loops where you have already validated the range, use []. When the index comes from outside your control, use at() so a bug becomes a clear exception instead of undefined behaviour.
How do I get the number of elements in a vector?
Call v.size(), which returns the current element count. To check whether a vector is empty, v.empty() is clearer and returns a bool. Do not confuse size() with capacity() — capacity is how much memory is reserved, which can be larger than the size.
Can a vector hold strings or my own objects?
Yes. A vector can hold any type: vector<string>, vector<double>, even vector<Student> for your own class. The only requirement is that the type can be copied or moved. For your own objects, emplace_back() can build them directly inside the vector.
How do I remove elements from a vector?
Use pop_back() to drop the last element, clear() to remove everything, or v.erase(v.begin() + i) to remove the element at index i. Erasing from the middle shifts the following elements down, so it is O(n); if order does not matter, swapping with the last element and then calling pop_back() is faster.
