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?
- Intent —
std::sort(v.begin(), v.end())says "sort this" — clearer than a hand-written sort. - Correctness — the algorithms are extensively tested.
- Performance — heavily optimized; often beat naive hand-written code.
- Composability — chain with iterators, transform, etc.
Common mistakes
- Off-by-one with iterators —
end()is one PAST the last element; never dereference it. - Modifying a container during iteration — invalidates iterators. Use the algorithms' own erase semantics.
- Forgetting erase-remove —
std::removealone leaves the container unchanged in size; you need.eraseto 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…