When coding in C++, one of the most common data structures you’ll encounter is the vector
.
It behaves like an array but with runtime flexibility — it can grow or shrink dynamically, making it one of the most powerful tools in the Standard Template Library (STL).
In this guide we’ll cover:
- Vectors and STL basics
- Initialization methods
- Common functions and operations
- Static vs dynamic allocation
- Array vs vector differences
- How vectors manage memory
- Iterators
- 2D vectors
- Performance considerations
- Comparison with other containers
- Automatic memory cleanup
- STL and Vectors
The Standard Template Library (STL) provides ready-made containers and algorithms. Some commonly used containers:
-
vector
→ Dynamic array -
queue
→ FIFO -
stack
→ LIFO -
set
→ Unique, ordered elements
👉 Compilation note: always use at least C++11:
g++ -std=c++11 code.cpp -o runfile && ./runfile
If you forget -std=c++11
, you may run into compile errors or unexpected runtime issues.
- Vector Initialization
Different ways to initialize std::vector
:
#include <iostream>
#include <vector>
using namespace std;
int main() {
// Direct initialization (C++11)
vector<int> v1 = {1, 2, 3};
// Fill constructor (size, initial_value)
vector<int> v2(3, 0); // [0, 0, 0]
// Empty then push_back
vector<int> v3;
v3.push_back(10);
v3.push_back(20);
// Printing using range-for loop
for (int x : v1) cout << x << " ";
cout << endl;
}
Output:
1 2 3
- Vector Functions & Operations
Common vector operations:
-
Insertion / Removal
-
push_back(x)
→ add at end -
pop_back()
→ remove last element
-
-
Access
-
v[i]
→ element by index (no bounds check) -
v.at(i)
→ bounds-checked access (throwsout_of_range
) -
front()
/back()
-
-
Information
-
size()
→ number of elements -
capacity()
→ allocated memory size -
empty()
→ check if empty
-
Example:
vector<int> v = {10, 20, 30};
v.push_back(40); // [10,20,30,40]
v.pop_back(); // [10,20,30]
cout << v.front() << endl; // 10
cout << v.back() << endl; // 30
cout << v.at(1) << endl; // 20
cout << v.size() << endl; // 3
cout << v.capacity() << endl; // capacity >= 3
- Static vs Dynamic Memory Allocation
Static arrays
int arr[5]; // size fixed at compile-time
- Usually stored on the stack
- Size rigid, cannot grow
Dynamic arrays (manual)
int* arr = new int[5];
delete[] arr;
- Stored on the heap
- Requires manual memory management
Vectors use dynamic memory under the hood but manage it automatically, making them safer and more flexible than raw dynamic arrays.
- Array vs Vector — Key Differences
Feature | Array (Static) | Vector (Dynamic) |
---|---|---|
Size | Fixed at compile-time | Can grow/shrink at runtime |
Memory location | Stack (usually) | Heap (managed internally) |
Memory management | Manual (if dynamic) | Automatic |
Functions available | None (raw access only) | Rich API: push_back , at , size ... |
Initialization | Limited forms | Flexible constructors |
Safety | No bounds checking |
at() provides bounds-checked access |
- How Vectors Work in Memory
vector
maintains two core concepts:
- size → number of stored elements
- capacity → allocated storage space (may be >= size)
When capacity is exceeded, implementations typically grow the capacity (commonly by doubling), which amortizes insertion costs.
Example:
vector<int> v;
for (int i = 0; i < 10; i++) {
v.push_back(i);
cout << "Size: " << v.size()
<< " Capacity: " << v.capacity() << endl;
}
Typical output (implementation-dependent):
Size: 1 Capacity: 1
Size: 2 Capacity: 2
Size: 3 Capacity: 4
Size: 5 Capacity: 8
Size: 9 Capacity: 16
Use reserve(n)
to pre-allocate memory if you know the expected size — this avoids repeated reallocations.
- Iterators
Iterators behave like pointers and are used to traverse containers:
vector<int> v = {10,20,30,40};
// Forward
for (auto it = v.begin(); it != v.end(); ++it) cout << *it << " ";
// Reverse
for (auto it = v.rbegin(); it != v.rend(); ++it) cout << *it << " ";
Output:
10 20 30 40
40 30 20 10
Iterators are the common way to use STL algorithms like std::sort
, std::find
, etc.
- 2D Vectors
Nested vectors are useful for matrices, graphs, and dynamic 2D storage:
vector<vector<int>> matrix(3, vector<int>(3, 0));
matrix[0][1] = 5;
matrix[2][2] = 7;
for (auto& row : matrix) {
for (auto val : row) cout << val << " ";
cout << endl;
}
Output:
0 5 0
0 0 0
0 0 7
- Performance Tips
-
size()
is O(1). Use it freely. -
capacity()
shows reserved memory; usereserve(n)
when you know the expected size. - Avoid excessive copying — prefer
emplace_back()
to construct in-place. - Random access is O(1); inserting/removing at the middle is O(n).
- For frequent front insertions, consider
deque
; for frequent middle insert/delete, considerlist
(but lists have poor cache locality).
- Vector vs Other Containers
- Vector → best for random access, fast end insertions.
- Deque → fast insertions at both ends.
- List → fast middle insertions/deletions (no random access).
- Set → unique, ordered elements (logarithmic operations).
👉 Default choice: vector
unless you have a specific reason to choose another container.
- Automatic Memory Cleanup
Vectors free their managed memory automatically when they go out of scope:
void func() {
vector<int> v(1000, 1);
} // memory is released when the function returns
✅ Conclusion
std::vector
is array-like but flexible, safe (with at()
), and efficient for most general-purpose needs. Prefer vectors over raw arrays unless you need a fixed-size, stack-allocated buffer or have very specific performance constraints.
Top comments (0)