The power of the Standard Template Library: std::sort, accumulate, max_element, count_if, std::map and lambda expressions.
Part of the C++ standard library is called the STL (Standard Template Library). It has three main parts: containers (data structures such as vector and map), algorithms (sort, find, accumulate…) and the iterators that connect them. Instead of writing your own sorting loop, you use ready-made tools that have been tested and optimized for years.
The idea of an iterator
A container's begin() method gives an iterator pointing to the first element, and its end() method gives one pointing one past the last element. Algorithms work on "the elements in this range": std::sort(v.begin(), v.end()). An iterator is similar to a pointer: you reach the element with *it.
Example: sensor data and stock
#include <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <string>
#include <vector>
int main() {
std::vector<double> readings = {23.5, 19.0, 25.2, 21.7, 30.1};
std::sort(readings.begin(), readings.end()); // smallest to largest
for (double x : readings) std::cout << x << ' ';
std::cout << '\n';
double sum = std::accumulate(readings.begin(), readings.end(), 0.0);
std::cout << "Average: " << sum / readings.size() << '\n';
auto largest = std::max_element(readings.begin(), readings.end());
std::cout << "Largest: " << *largest << '\n';
// Lambda: count the values above the threshold
int hot = std::count_if(readings.begin(), readings.end(),
[](double x) { return x > 24.0; });
std::cout << "Above 24 C: " << hot << " readings\n";
// Custom sort with a lambda: largest to smallest
std::sort(readings.begin(), readings.end(),
[](double a, double b) { return a > b; });
std::cout << "Hottest: " << readings.front() << '\n';
// std::map: key -> value
std::map<std::string, int> stock;
stock["resistor"] = 120;
stock["led"] = 300;
stock["capacitor"] = 45;
stock["resistor"] += 30;
for (const auto& [name, qty] : stock) {
std::cout << name << ": " << qty << '\n';
}
return 0;
}
19 21.7 23.5 25.2 30.1
Average: 23.9
Largest: 30.1
Above 24 C: 2 readings
Hottest: 30.1
capacitor: 45
led: 300
resistor: 150
Let's read the code piece by piece
sort and accumulate
std::sort sorts from smallest to largest by default. std::accumulate adds up the elements starting from an initial value (here 0.0); its header is <numeric>. We wrote the initial value as 0.0, not 0, because if it were written as an int, the whole sum would be computed as an int and the decimals would be lost.
max_element
It returns not the element itself but an iterator; to get the value you write *largest. There is also min_element.
Lambda expressions
A lambda is a nameless function written in place: [capture](parameters) { body }. The expression [](double x) { return x > 24.0; } is a small function that asks "is x greater than 24?". The square brackets specify how variables from outside are brought into the lambda: [threshold] copies the value, [&threshold] takes it by reference, and [=] and [&] capture everything. This way you can supply the threshold value from outside:
double threshold = 24.0;
int count = std::count_if(readings.begin(), readings.end(),
[threshold](double x) { return x > threshold; });
std::map
std::map keeps key-value pairs sorted by key; that is why the loop printed capacitor, led, resistor in alphabetical order. You access an entry with stock["led"]. Careful: if the key does not exist, the [] operator creates it with a zero value. To only check, use stock.count("led") or stock.find("led"). The form for (const auto& [name, qty] : stock) is C++17's structured binding feature and splits the pair into two names. If you don't need sorting, std::unordered_map (header: <unordered_map>) is faster on average.
Why the STL?
- Correctness: A sorting loop you write by hand is quite likely to contain a bug; the STL has been battle-tested.
- Speed:
std::sortruns in n log n time on average and is well optimized. - Readability: A
std::count_if(...)line says what it does; a hand-written loop has to be deciphered.
The beginner's rule for which container to choose when is simple: the default choice is std::vector. If you need to look things up by key, use std::map or std::unordered_map. To keep unique elements in sorted order, use std::set. To choose anything else, you should have a reason proven by measurement.
Algorithms trust their ranges. Dereferencing the end() iterator (for example, using the result of max_element on an empty vector with * without checking it) is undefined behavior. On an empty range max_element returns end(); check that the vector is not empty first.
Try it yourself
- Calculate the average of each of three reading vectors with
accumulate. - Count the readings smaller than 20 with
count_ifand a lambda; supply the threshold through a variable. - Keep a "sensor name -> last reading" table with
std::map<std::string, double>and print all of it. - Use
std::findto check whether a particular value is in the vector.
// Mini quiz
Click an option; you will see right away, with the reason, whether it is correct or not.
Mark it when you finish: your progress is saved and you earn +20 XP.
Tip: ← → keys let you move between lessons.