Skip to content
STL Algorithms in Depth
step 1/6

Reading — step 1 of 6

Learn

~2 min readTemplates and STL Algorithms

The STL <algorithm> header is one of C++'s greatest assets: ~100 generic algorithms that work on any iterator-pair. Learn it well and your loops mostly disappear.

The iterator-pair pattern

Most algorithms take a begin iterator and an end iterator (half-open range):

#include <algorithm>
#include <vector>

std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
std::sort(v.begin(), v.end());          // sort in place

With C++20 ranges (std::ranges::sort(v)), the syntax is shorter, but the iterator-pair form works everywhere.

Search and find

auto it = std::find(v.begin(), v.end(), 5);
if (it != v.end()) {
    std::cout << "found at index " << (it - v.begin());
}

auto found = std::find_if(v.begin(), v.end(), [](int x) { return x > 4; });

bool any = std::any_of(v.begin(), v.end(), [](int x) { return x < 0; });
bool all = std::all_of(v.begin(), v.end(), [](int x) { return x > 0; });

int count = std::count(v.begin(), v.end(), 1);            // count occurrences
int countMatching = std::count_if(v.begin(), v.end(),
                                   [](int x) { return x > 3; });

Transformations

std::vector<int> doubled(v.size());
std::transform(v.begin(), v.end(), doubled.begin(),
               [](int x) { return x * 2; });

std::vector<int> sorted = v;
std::sort(sorted.begin(), sorted.end());

std::sort(v.begin(), v.end(), std::greater<int>());     // descending
std::sort(v.begin(), v.end(),
          [](int a, int b) { return a < b; });          // custom

Numeric algorithms

#include <numeric>

int sum = std::accumulate(v.begin(), v.end(), 0);
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<>());
int maxVal = *std::max_element(v.begin(), v.end());
int minVal = *std::min_element(v.begin(), v.end());

Removing elements — the erase-remove idiom

The algorithms that "remove" don't actually shrink the container — they shift unwanted elements to the end and return a new logical end:

std::vector<int> v = {1, 2, 3, 2, 4, 2};
v.erase(std::remove(v.begin(), v.end(), 2), v.end());   // v is now {1, 3, 4}

In C++20: std::erase(v, 2); does both steps. Cleaner.

Other classics

std::reverse(v.begin(), v.end());
std::rotate(v.begin(), v.begin() + 3, v.end());     // rotate left by 3
std::unique(v.begin(), v.end());                     // remove ADJACENT duplicates
std::next_permutation(v.begin(), v.end());           // generate next lex perm
std::partition(v.begin(), v.end(), [](int x) { return x % 2 == 0; });

Why use STL algorithms instead of for loops?

  1. Intentstd::sort(v.begin(), v.end()) says "sort this" — clearer than a hand-written sort.
  2. Correctness — the algorithms are extensively tested.
  3. Performance — heavily optimized; often beat naive hand-written code.
  4. Composability — chain with iterators, transform, etc.

Common mistakes

  • Off-by-one with iteratorsend() is one PAST the last element; never dereference it.
  • Modifying a container during iteration — invalidates iterators. Use the algorithms' own erase semantics.
  • Forgetting erase-removestd::remove alone leaves the container unchanged in size; you need .erase to actually shrink.
  • Custom comparators that aren't strict weak orderings — sorting may misbehave or infinite-loop. The comparator must implement < consistently.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…