Iterators provide a uniform way to traverse any STL container, and the <algorithm> header builds a huge library of generic operations on top of them.
#include <vector>
#include <algorithm>
std::vector<int> nums = {5, 2, 8, 1, 9};
std::sort(nums.begin(), nums.end()); // sorts in place: {1,2,5,8,9}
auto it = std::find(nums.begin(), nums.end(), 8); // returns an iterator to 8
if (it != nums.end()) {
std::cout << "Found at position " << (it - nums.begin()) << "\n";
}
int count = std::count(nums.begin(), nums.end(), 2); // how many times 2 appears
auto maxIt = std::max_element(nums.begin(), nums.end()); // iterator to the largest element
std::sort(nums.begin(), nums.end(), [](int a, int b) { // custom comparator via lambda
return a > b; // descending order instead of the default ascending
});
An iterator is an object that behaves like a generalized pointer — *it dereferences to get the current element, ++it advances to the next one — and every STL container exposes .begin() (the first element) and .end() (one past the last element, used as a sentinel, never dereferenced) so algorithms can work identically across vector, list, set, and more without knowing the container's internal layout.
Almost every common operation — searching, sorting, counting, transforming, accumulating — already exists as a well-tested, generic function in <algorithm> (or <numeric> for things like std::accumulate), and reaching for these instead of hand-writing loops is both less error-prone and, in idiomatic modern C++, generally the preferred style. Many algorithms accept an optional final argument — often a lambda (covered in the Modern C++ chapter) — that customizes their behavior, as with the descending-order sort above.