5.2.20 · D1C++ Programming

Foundations — STL algorithms — sort, find, transform, accumulate, copy, all_of, any_of

1,836 words8 min readBack to topic

This page assumes you have never seen an iterator, a lambda, or the notation [first, last). We build each symbol from a picture before the parent note is allowed to use it. Parent: STL algorithms — the topic.


0. What is a container? (the shelf of boxes)

Before any symbol, picture the thing we operate on.

Figure — STL algorithms — sort, find, transform, accumulate, copy, all_of, any_of

Look at the figure: five boxes hold 10, 20, 30, 40, 50. The number under each box is its index — box 0 is the first. This numbering-from-zero is the seed of everything below.


1. The iterator — a finger pointing at a box

The parent note says algorithms take "a pair of iterators." What is an iterator?

Figure — STL algorithms — sort, find, transform, accumulate, copy, all_of, any_of

In the figure the cyan finger it points at box 2 (value 30). Writing *it gives 30. Writing ++it slides the finger to box 3. That is the whole interface an algorithm needs: read here, step forward. See Iterators and ranges for the full family.


2. begin() and end() — where the fingers start and stop

Figure — STL algorithms — sort, find, transform, accumulate, copy, all_of, any_of

The figure shows begin() on box 0 and end() hovering just after box 4 — on the imaginary "box 5" slot. end() never points at a real value. Never write *v.end(); the finger is over the cliff.


3. The half-open range [first, last) — the two-marker span

Now the parent note's central symbol. The bracket shapes carry meaning.

Figure — STL algorithms — sort, find, transform, accumulate, copy, all_of, any_of

In the figure the amber span covers boxes 0,1,2first = begin() sits on box 0, last sits on box 3, and box 3 is not painted because ) excludes it.


4. *it and it - v.begin() — reading and locating

Two small pieces of notation the parent uses in examples.

If a finger sits on box 2, then it - v.begin() is . That is exactly the parent's size_t idx = it - v.begin(); trick — subtract the start-finger to convert a location into a number. This subtraction only works for random-access containers (rows in memory), which brings us to the next idea.


5. Random-access vs. one-step-at-a-time (why sort needs a vector)


6. The "recipe" you hand the loop — predicates and operations

Algorithms like sort, find, all_of take a little function that decides things. What is that?

Figure — STL algorithms — sort, find, transform, accumulate, copy, all_of, any_of

The figure shows a box entering a small machine labelled pred; out comes a light: green true or grey false. That machine is what all_of and any_of feed every box through.

There are three ways to write such a mini-function, from oldest to newest:

  • a plain named function,
  • a function object (functor) — an object with a () you can call,
  • a lambda — an inline throwaway function written right at the call site, [](int x){ return x % 2 == 0; }.

The parent uses lambdas everywhere: [](int a, int b){ return a > b; }. Read it as "given a and b, answer with a > b." The [] is where the lambda begins.


7. % and truncation — the sneaky arithmetic in the examples


The prerequisite map

Container - row of boxes

Iterator - a finger

begin and end fingers

Half-open range first to last

star it - read a box

it minus begin - the index

random access - jump and subtract

predicate - yes or no machine

lambda - inline recipe

binary op - combine two values

STL algorithms

percent and truncation

Read top-to-bottom: boxes give rise to fingers, fingers give rise to markers and ranges, and ranges plus recipes feed the seven algorithms.


Equipment checklist

Cover the right side and answer; reveal to check.

A container (vector) is best pictured as
a numbered row of boxes, first box at index 0.
An iterator is
a finger that points at one box; *it reads it, ++it moves it forward one.
v.begin() points at
the first box (index 0).
v.end() points at
one box PAST the last — empty space, never a real value.
The brackets in [first, last) mean
[ = first is included, ) = last is excluded (it is the stop-signal).
The number of elements in [first, last) equals
last - first, no +1 needed.
An empty range looks like
first == last.
it - v.begin() gives you
the index (how many steps from the start); works only for random-access.
Why can't you std::sort a std::list?
sort needs random-access fingers that can jump; a list finger moves only one step at a time.
A predicate is
a mini-function returning true/false about one element.
A lambda [](int x){ return x % 2 == 0; } reads as
"given x, answer whether x is even."
Why does accumulate(..., 0) truncate over doubles?
the running total's type equals init's type; int 0 means an int accumulator that chops fractions — use 0.0.