The C++ STL Explained

    Atul Kabra4 min readUpdated

    The Standard Template Library (STL) is the collection of ready-made data structures and algorithms that ships with C++. It is built from three cooperating pieces: containers that hold your data, iterators that walk over it, and algorithms that operate on it through those iterators. Together they let you write std::sort(v.begin(), v.end()) instead of hand-coding a sort — less code, fewer bugs, and battle-tested performance.

    Here is the big picture, then each piece.

    The three pillars

    • Containers store collections of objects — std::vector (dynamic array), std::map (key-value), std::set (unique sorted values), std::list, and more.
    • Iterators are objects that point into a container and can move forward (and sometimes back). They are the glue between containers and algorithms.
    • Algorithms are free functions like std::sort, std::find, and std::count that work on a range of iterators, not on a specific container type.

    Because algorithms talk to iterators rather than containers directly, one std::sort works on a vector, a deque, or an array.

    Putting them together

    #include <algorithm>
    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> marks{72, 95, 60, 88, 95};
    
        // algorithm + iterators: sort the whole container
        std::sort(marks.begin(), marks.end());
    
        // algorithm: find a value, returns an iterator
        auto it = std::find(marks.begin(), marks.end(), 88);
        if (it != marks.end()) {
            std::cout << "Found 88 at index "
                      << (it - marks.begin()) << "\n";
        }
    
        // algorithm: count occurrences
        std::cout << "95 appears "
                  << std::count(marks.begin(), marks.end(), 95)
                  << " times\n";
    
        // range-based for: iterators behind the scenes
        for (int m : marks) {
            std::cout << m << " ";
        }
        std::cout << "\n";
    }
    

    Output:

    Found 88 at index 3
    95 appears 2 times
    60 72 88 95 95
    

    Notice the pattern: nearly every algorithm takes begin() and end() — the half-open range [begin, end) that covers the whole container.

    Picking a container

    NeedReach for
    A resizable array, fast random accessstd::vector
    Key-value lookups, sorted keysstd::map
    Key-value lookups, fastest averagestd::unordered_map
    Unique values, sortedstd::set
    Frequent inserts at both endsstd::deque

    When in doubt, start with std::vector — it is the right default surprisingly often.

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses

    Why prefer algorithms over hand-written loops

    std::sort, std::find, and friends are correct, optimised, and express intent clearly. Reading std::any_of(...) tells the reader exactly what is happening; a raw loop makes them decode it. The modern C++ guideline is: prefer a named algorithm to a hand-rolled loop whenever one exists.

    A note on ranges (C++20)

    C++20 added the ranges library, which lets you call algorithms on a container directly: std::ranges::sort(marks); instead of passing two iterators. It is cleaner and harder to get wrong, and worth adopting once you understand the iterator model underneath.

    Algorithms that take a function

    Many of the most useful algorithms accept a small function — often a lambda — that customises what they do. This is how you sort by a custom rule or filter by a condition.

    #include <algorithm>
    #include <vector>
    #include <iostream>
    
    int main() {
        std::vector<int> v{5, 1, 4, 2, 3};
    
        // sort in descending order using a lambda comparator
        std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
    
        // count how many values are greater than 2
        auto big = std::count_if(v.begin(), v.end(), [](int x) { return x > 2; });
    
        std::cout << "first: " << v.front() << ", big count: " << big << "\n";
    }
    

    This combination — a generic algorithm plus a tiny inline function describing your intent — is the everyday idiom of modern C++. It reads almost like a sentence: "sort these, descending"; "count those greater than two."

    Common mistakes

    • Mismatched iterator pairs. Passing a.begin() and b.end() from two different containers is undefined behaviour. Always pair begin/end from the same container.
    • Using an iterator after modifying the container. Inserting into or erasing from a vector can invalidate existing iterators. Re-fetch them after changes.
    • Forgetting to check end(). std::find returns the end iterator when nothing matches; dereferencing it is a bug.
    • Reinventing standard algorithms. Hand-writing a sort or a search is slower to write and easier to get wrong than calling the STL.

    FAQ

    What are the three main parts of the STL? Containers (hold data), iterators (point into and traverse data), and algorithms (operate on ranges of iterators). They are designed to plug into each other.

    Is std::string part of the STL? std::string lives in the standard library and works with STL algorithms via its iterators, though historically it is grouped with the strings library rather than the core STL containers.

    Keep learning

    Learn the STL hands-on with mentors in Jalgaon — join the waitlist for our C++ Programming course.

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses
    Atul Kabra

    Founder, Infoplanet

    Atul Kabra founded Infoplanet in 2001 and has spent over two decades teaching programming — C, C++, Java, databases and more — to students across Maharashtra.

    Related guides