Skip to content
Home
C++ STL: Containers, Algorithms, and Iterators

C++ STL: Containers, Algorithms, and Iterators

C/C++ C/C++ 8 min read 1503 words Beginner David Chen

The C++ Standard Template Library (STL) is a collection of generic containers, algorithms, and iterators. It is the standard library’s most influential part — designed by Alexander Stepanov in the 1990s, it separates data structures from algorithms using iterators as a glue layer. Understanding the STL is essential for writing idiomatic, efficient C++.

This guide covers the most commonly used STL components with practical examples.

Containers

Sequence Containers

#include <vector>
#include <deque>
#include <list>
#include <array>
#include <forward_list>

// vector — dynamic array, contiguous memory
std::vector<int> vec = {1, 2, 3, 4, 5};
vec.push_back(6);            // O(1) amortized
vec.pop_back();              // O(1)
vec.insert(vec.begin() + 2, 99);  // O(n)
vec.erase(vec.begin());      // O(n)
vec[3] = 42;                 // O(1) random access

// deque — double-ended queue
std::deque<int> deq = {1, 2, 3};
deq.push_front(0);           // O(1)
deq.push_back(4);            // O(1)
deq.pop_front();             // O(1)

// list — doubly-linked list
std::list<int> lst = {1, 2, 3};
lst.push_front(0);
lst.push_back(4);
lst.insert(++lst.begin(), 99);  // O(1) at iterator position

// array — fixed-size, stack-allocated
std::array<int, 5> arr = {10, 20, 30, 40, 50};
// arr.size() == 5, no dynamic allocation

Associative Containers

#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>

// set — ordered, unique keys (usually red-black tree)
std::set<int> s = {3, 1, 4, 1, 5, 9};  // {1, 3, 4, 5, 9}
s.insert(2);
s.erase(1);
bool exists = s.contains(4);  // C++20

// map — ordered key-value pairs
std::map<std::string, int> ages;
ages["Alice"] = 30;
ages["Bob"] = 25;
// ages is ordered alphabetically by key

// unordered_set — hash table, O(1) average
std::unordered_set<int> us = {3, 1, 4, 1, 5};

// unordered_map — hash table key-value
std::unordered_map<std::string, int> scores;
scores["player1"] = 100;
scores["player2"] = 85;

Container Adaptors

#include <stack>
#include <queue>

// stack — LIFO
std::stack<int> st;
st.push(1);
st.push(2);
st.top();    // 2
st.pop();    // removes 2

// queue — FIFO
std::queue<int> q;
q.push(1);
q.push(2);
q.front();   // 1
q.back();    // 2
q.pop();     // removes 1

// priority_queue — max-heap by default
std::priority_queue<int> pq;
pq.push(3);
pq.push(1);
pq.push(5);
pq.top();    // 5

Iterators

Iterators bridge containers and algorithms. They come in different categories:

#include <iterator>

std::vector<int> vec = {10, 20, 30, 40, 50};

// Basic iteration
for (auto it = vec.begin(); it != vec.end(); ++it) {
    std::cout << *it << ' ';
---

// Range-based for (uses iterators internally)
for (const auto& v : vec) {
    std::cout << v << ' ';
---

// Iterator categories
auto it = vec.begin();
++it;          // Forward iterator (all containers)
--it;          // Bidirectional (list, set, map)
it += 3;       // Random access (vector, deque, array)
auto diff = it - vec.begin();  // Distance (random access)

// Reverse iteration
for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
    std::cout << *it << ' ';  // 50, 40, 30, 20, 10
---

// Iterator utilities
std::advance(it, 2);          // Advance by n
auto dist = std::distance(vec.begin(), it);  // Distance between iterators

Algorithms

#include <algorithm>
#include <numeric>

std::vector<int> v = {5, 2, 8, 1, 9, 3, 7, 4, 6};

// Sorting
std::sort(v.begin(), v.end());               // {1, 2, 3, 4, 5, 6, 7, 8, 9}
std::partial_sort(v.begin(), v.begin() + 3, v.end());  // Top 3 sorted

// Searching
auto it = std::find(v.begin(), v.end(), 5);
bool exists = std::binary_search(v.begin(), v.end(), 5);  // Requires sorted range

// Modifying
std::fill(v.begin(), v.end(), 0);            // Set all to 0
std::transform(v.begin(), v.end(), v.begin(),
               [](int x) { return x * 2; }); // Double each element

// Removing
auto new_end = std::remove(v.begin(), v.end(), 0);
v.erase(new_end, v.end());                   // Erase-remove idiom

// Min/Max
auto [min_it, max_it] = std::minmax_element(v.begin(), v.end());

// Counting
int count = std::count(v.begin(), v.end(), 5);

// Numeric algorithms (in <numeric>)
int sum = std::accumulate(v.begin(), v.end(), 0);
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<>());
std::vector<int> diffs;
std::adjacent_difference(v.begin(), v.end(), std::back_inserter(diffs));

Common Patterns

Erase-Remove Idiom

// Remove all elements matching a value
std::vector<int> vec = {1, 2, 3, 2, 4, 2, 5};
vec.erase(
    std::remove(vec.begin(), vec.end(), 2),
    vec.end()
);
// vec == {1, 3, 4, 5}

// Remove elements satisfying a predicate
vec.erase(
    std::remove_if(vec.begin(), vec.end(),
                   [](int x) { return x % 2 == 0; }),
    vec.end()
);

Custom Comparators

struct Person {
    std::string name;
    int age;
---;

// Sort by age descending, then name ascending
std::sort(people.begin(), people.end(),
    [](const Person& a, const Person& b) {
        if (a.age != b.age) return a.age > b.age;
        return a.name < b.name;
    });

// Custom set with comparator
auto cmp = [](const Person& a, const Person& b) {
    return a.name < b.name;
---;
std::set<Person, decltype(cmp)> person_set(cmp);

Efficient Insertion

std::map<std::string, int> scores;

// Insert only if key doesn't exist
auto [it, inserted] = scores.try_emplace("Alice", 100);
if (inserted) {
    std::cout << "Inserted new entry\n";
---

// Get or insert default
int& score = scores["Bob"];  // Creates with 0 if not exists

// Insert with hint (for ordered containers)
auto hint = scores.lower_bound("Charlie");
scores.emplace_hint(hint, "Charlie", 50);

Performance Considerations

| Container | Insert | Erase | Find | Random Access | |

Container Selection Guide

Choosing the right container is critical for performance. Each STL container makes different trade-offs:

| Container | Insert | Erase | Find | Ordering | Iterator invalidation | |

FAQ

What is the difference between malloc and new in C++? malloc allocates raw memory without calling constructors; new allocates memory and calls the constructor. In C++, prefer new for objects. free vs delete follows the same pattern — delete calls the destructor.

How do I prevent memory leaks in C/C++? Use RAII (Resource Acquisition Is Initialization) in C++ — smart pointers like std::unique_ptr and std::shared_ptr automatically free memory. In C, always pair every malloc with a free and use tools like Valgrind or AddressSanitizer to detect leaks.

What is undefined behavior in C/C++? Undefined behavior occurs when code performs operations that the language standard does not define — dereferencing a null pointer, buffer overflow, signed integer overflow. The compiler may generate any code, including unexpected results or crashes.

Should I learn C or C++ first? Learn C first if you want to understand low-level memory and system programming. Learn C++ first if you want object-oriented features and the STL. Both are valuable; C++ builds on C concepts.

What is the difference between a header file and a source file? Header files (.h) declare interfaces — function prototypes, class definitions, macros. Source files (.c or .cpp) implement the declarations. Headers are #included; source files are compiled separately and linked.

———–|——–|——-|——|———-|———————-| | vector | O(1) at end | O(1) at end | O(n) | Insertion order | On reallocation | | deque | O(1) at ends | O(1) at ends | O(n) | Insertion order | Never invalidates elements | | list | O(1) anywhere | O(1) anywhere | O(n) | Insertion order | Never invalidates | | set/map | O(log n) | O(log n) | O(log n) | Sorted | Never invalidates | | unordered_set/unordered_map | O(1) avg | O(1) avg | O(1) avg | None | On rehash |

Iterators and Ranges

STL iterators provide a uniform interface for traversing containers. C++20 ranges simplify iteration further:

std::vector<int> v = {1, 2, 3, 4, 5};

// Traditional iterators
for (auto it = v.begin(); it != v.end(); ++it) { }

// Range-based for loop
for (int x : v) { }

// C++20 ranges
auto even = v | std::views::filter([](int x) { return x % 2 == 0; });
for (int x : even) { }

Algorithms Library

The <algorithm> header provides generic algorithms that operate on iterators. These are more expressive and less error-prone than hand-written loops:

std::vector<int> data = {5, 2, 8, 1, 9, 3};
std::sort(data.begin(), data.end());           // Sort
auto it = std::lower_bound(data.begin(),       // Binary search
    data.end(), 5);
std::transform(data.begin(), data.end(),        // Apply function
    data.begin(), [](int x) { return x * 2; });

Allocators

Allocators manage memory for containers. The default std::allocator uses new and delete. Custom allocators enable pool allocation, arena allocation, and NUMA-aware memory management for specialized use cases.

string_view and span

C++17 introduced std::string_view (non-owning string reference) and C++20 added std::span (non-owning contiguous sequence view). These types eliminate copies when passing read-only references to strings and arrays:

void parse(std::string_view sv) {
    // No copy — sv points to the original string
---
std::string s = "hello";
parse(s);  // Implicit conversion, no allocation

———–|——–|——-|——|—————| | vector | O(n) | O(n) | O(n) | O(1) | | deque | O(1)* | O(n) | O(n) | O(1) | | list | O(1) | O(1) | O(n) | O(n) | | set/map | O(log n) | O(log n) | O(log n) | — | | unordered_set/map | O(1) avg | O(1) avg | O(1) avg | — |

  • Use vector by default — it’s cache-friendly and fast
  • Use unordered_map for key-value lookups (hash table)
  • Use set/map when you need ordering
  • Use list only when you need O(1) insert/erase at arbitrary positions

Conclusion

The STL is the foundation of modern C++. Master vector, unordered_map, and set as your go-to containers. Learn the algorithm functions — sort, find, transform, accumulate — they eliminate loops and make your code clearer. Use iterators to bridge containers and algorithms, and always prefer STL algorithms over handwritten loops.

Related: Check our C++ OOP guide.

For a comprehensive overview, read our article on C File Io Guide.

Section: C/C++ 1503 words 8 min read Beginner 1251 articles in section Report inaccuracy Back to top
DC
David Chen Technology Editor

Technology Editor at ExcellentWiki covering programming, engineering, and consumer technology topics.

View author profile →