Named algorithms are clearer, tested and often faster than raw loops, and every C++ reviewer expects you to know them.
The headers <algorithm> and <numeric> hold over a hundred generic algorithms that operate on iterator ranges, usually customised with a lambda. Knowing the common ones turns ten-line loops into one line that states its intent.
- Searching:
find,find_if,any_of/all_of/none_of,count_if, and on sorted rangesbinary_search,lower_bound,equal_range. - Sorting:
sort(not stable),stable_sort,partial_sort,nth_element(k-th element in O(n)),is_sorted. - Transforming:
transform,copy_if,fill,iota,reverse,rotate,unique. - Reducing:
accumulateandreduce(<numeric>),min_element,max_element,minmax_element.
Comparators must define a strict weak ordering: use <, never <=, or std::sort can misbehave and even crash.
Algorithms never change the size of a container, since they only see iterators. remove_if and unique move kept elements to the front and return the new logical end; you must then call erase to shrink the container (the erase-remove idiom). For the remove case, C++20's std::erase_if does both steps.
Watch accumulate's initial value: its type is the type of the accumulator, so accumulate(v.begin(), v.end(), 0) over doubles truncates every step to int. Pass 0.0.
Output algorithms like transform and copy write to an output iterator and assume there's room: size the destination first or use std::back_inserter(dest).
Since C++17, many algorithms accept an execution policy such as std::execution::par to run in parallel. The C++20 range versions in the Advanced lessons take whole containers instead of iterator pairs.
Example
#include <algorithm>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
struct Order { std::string customer; double amount; };
int main() {
std::vector<Order> orders{{"ann", 30.0}, {"bob", 120.5}, {"cy", 75.0}, {"ann", 9.5}};
std::sort(orders.begin(), orders.end(),
[](const Order& a, const Order& b) { return a.amount > b.amount; });
std::cout << orders.front().customer << '\n'; // bob
double total = std::accumulate(orders.begin(), orders.end(), 0.0, // 0.0, not 0!
[](double sum, const Order& o) { return sum + o.amount; });
bool any_big = std::any_of(orders.begin(), orders.end(),
[](const Order& o) { return o.amount > 100; });
std::vector<std::string> names;
std::transform(orders.begin(), orders.end(), std::back_inserter(names),
[](const Order& o) { return o.customer; });
std::sort(names.begin(), names.end());
names.erase(std::unique(names.begin(), names.end()), names.end()); // dedupe
std::cout << total << ' ' << any_big << ' ' << names.size() << '\n'; // 235 1 3
}Remember
- Prefer a named algorithm to a raw loop: it states intent
remove_if/uniquedon't shrink the container — follow witherase(or usestd::erase_if)- Comparators must be strict (
<), andaccumulate's initial value sets the result type
Watch out for
- Passing
0instead of0.0tostd::accumulateover doubles, silently truncating the sum.