Step by step: from arrays to STL containers

Step by step: from arrays to STL containers

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 

  1. Never use C-style arrays in new code (except when interfacing with C APIs).
  2. For small fixed-size data — use std::array.
  3. For most tasks — use std::vector.
  4. For fast key-based lookup — use std::unordered_map.
  5. 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

Digital circuit design with glowing green elements on a dark background
Back to blog