~100 ready-made functions in <algorithm> and <numeric> that replace hand-written loops. Learn ~15 and you'll reach for them instead of writing for by hand.
Most loops you'd write by hand already exist as a named, tested, optimized algorithm. sort, find, transform, accumulate, count_if — they take a range plus (often) a small function, and say what you mean instead of how to loop.
Almost all of them follow one pattern: a range (begin, end), then optionally a value to look for or a callable (a predicate or operation — usually a lambda, Lesson 9). They return an iterator, a count, or write into a destination.
#include <algorithm> std::vector<int> v = {5, 3, 1, 4, 2}; std::sort(v.begin(), v.end()); // {1,2,3,4,5} auto it = std::find(v.begin(), v.end(), 3); // iterator to the 3 int n = std::count_if(v.begin(), v.end(), [](int x){ return x > 2; }); // 3 elements > 2
Source: Core Guidelines P.1/SL — express intent; prefer algorithms.
| Group | Algorithm | Does |
|---|---|---|
| Search | find / find_if | first element equal to / matching a predicate |
count / count_if | how many equal / match | |
any_of / all_of / none_of | does any / every / no element match? | |
binary_search / lower_bound | fast lookup in a sorted range (O(log n)) | |
| Order | sort / stable_sort | sort (stable keeps equal-elements' order) |
nth_element / partial_sort | partial ordering (e.g. top-K) without full sort | |
min_element / max_element | iterator to the smallest / largest | |
| Modify | transform | map each element through a function into a destination |
copy / fill / replace | copy a range / set all to a value / swap a value | |
remove_if + erase / unique | drop matching / collapse adjacent duplicates (§04) | |
Numeric<numeric> | accumulate / reduce | fold a range to one value (sum, product…) |
iota | fill with increasing values (0,1,2,…) |
<numeric> is a separate header
accumulate, reduce, iota, and inner_product live in <numeric>, not <algorithm>. Forgetting the include is a common "why won't it compile" moment.Source: cppreference — Algorithms · Numeric. Full quick list in the cheat sheet.
// sort descending — pass a comparator lambda (returns "a before b?") std::sort(v.begin(), v.end(), [](int a, int b){ return a > b; }); // sort people by age std::sort(people.begin(), people.end(), [](const Person& a, const Person& b){ return a.age < b.age; });
#include <numeric> int sum = std::accumulate(v.begin(), v.end(), 0); // 0 + each → total int prod = std::accumulate(v.begin(), v.end(), 1, std::multiplies<>()); // 1 * each → product
accumulate is the starting value and sets the result type. accumulate(v.begin(), v.end(), 0) accumulates in int; for doubles use 0.0, or you'll silently truncate.auto lengths = std::vector<size_t>{}; std::transform(words.begin(), words.end(), std::back_inserter(lengths), [](const std::string& w){ return w.size(); }); // lengths now holds the length of each word; back_inserter push_backs results
Source: cppreference — accumulate, transform.
This one trips up everyone once. std::remove_if does not remove anything — it can't, because an algorithm only has iterators, not the container. It shuffles the "kept" elements to the front and returns an iterator to the new logical end; the container's size() is unchanged until you actually erase the tail.
// PRE-C++20: the classic two-step "erase-remove" idiom v.erase(std::remove_if(v.begin(), v.end(), [](int x){ return x % 2 == 0; }), // move evens to back v.end()); // erase them // C++20: one line does both std::erase_if(v, [](int x){ return x % 2 == 0; });
remove_if alone is a no-op-looking bug
Calling std::remove_if(...) and ignoring the return leaves the container the same size with garbage at the end. Always pair it with erase — or use C++20 std::erase_if / std::erase, which exist precisely to kill this footgun.Source: cppreference — remove/remove_if & std::erase / erase_if.
std::find / std::sort over a hand-written loop?std::remove_if(v.begin(), v.end(), pred) with no erase, what is v.size()?std::accumulate(v.begin(), v.end(), 0) on a vector of doubles loses the fractional parts. Why?accumulate and iota?begin, end), then optionally a value to match or a callable (predicate/operation). Returns an iterator, count, or writes to a destination.sort, find/find_if, count_if, any_of/all_of, transform, accumulate, min_element/max_element, remove_if+erase.remove_if actually do?erase, or use C++20 std::erase_if.sort(b, e, [](auto& a, auto& b){ return a < b; }) — return true if a should come before b.<numeric> (not <algorithm>): accumulate, reduce, iota, inner_product. The init value sets the result type.std::ranges::sort(v) / std::ranges::find(v, x) take the container directly — same algorithms, no begin/end (C++20).Best drill: paste me a hand-written loop and ask "which algorithm replaces this?" Or try "top 3 scores without fully sorting" (hint: partial_sort/nth_element). Next: the lambdas these algorithms eat.