Step by step: from arrays to STL containers
Share
Most developers begin their journey with C++ by learning arrays. This makes sense — arrays are simple and straightforward. However, as soon as a project grows even slightly more complex, raw arrays quickly turn into a source of bugs, memory leaks, and maintenance headaches.
In this article, we’ll walk through the complete evolution: from classic C-style arrays to modern STL containers. You’ll understand when and why you should stop using raw arrays and which container to choose in each specific situation.
1. Why arrays are just the beginning
C-style arrays (int arr[10];) have serious drawbacks:
- Fixed size (cannot be changed at runtime)
- No bounds checking
- Automatic decay into a pointer
- Manual memory management
This is exactly why modern C++ has almost completely moved away from raw arrays in favor of STL containers.
2. Step by step: the evolution of the approach
Step 1: C-style arrays
int arr[5] = {10, 20, 30, 40, 50};
Step 2: std::array (C++11) — a safer fixed-size array
#include <array>
std::array<int, 5> arr = {10, 20, 30, 40, 50};
Advantages:
- Knows its own size (arr.size())
- Supports iterators
- Does not decay into a pointer automatically
Step 3: std::vector — dynamic array
#include <vector>
std::vector<int> vec = {10, 20, 30};
vec.push_back(40); // automatically grows
vec.reserve(100); // reserve memory in advance
Step 4: Associative containers
- std::set — unique sorted elements
- std::map — key-value pairs, sorted by key
Step 5: Unordered containers (C++11)
- std::unordered_map — fastest lookup (average O(1))
- std::unordered_set
3. Container comparison (when to use what)
| Task | Best Container | Why |
|---|---|---|
| Fixed size needed | std::array | Speed + safety |
| Frequent insert/delete | std::vector | Dynamic size |
| Fast lookup required | std::unordered_map | Average O(1) |
| Need sorted data | std::set or std::map | Automatic sorting |
| Need a queue | std::deque | Fast operations on both ends |
4. Practical recommendations
- Never use C-style arrays in new code (except when interfacing with C APIs).
- For small fixed-size data — use std::array.
- For most tasks — use std::vector.
- For fast key-based lookup — use std::unordered_map.
- Always use .at() instead of [] during debugging to catch out-of-bounds errors.
5. Example: moving from array to STL
Old code (bad):
int scores[100];
int count = 0;
// ... filling the array
Modern code (good):
std::vector<int> scores;
scores.reserve(100); // optimize memory allocation
// ... filling the vector
