17.1. Background¶
Recall from Container classes that a container is a generic collection. Containers allow us to store data using well-known data structures. The STL containers provide the patterns we can use to make custom containers, if needed.
Recall from Iterable ADT’s that an iterator is a type that performs operations that feel like a pointer. Although an iterator allows syntax very similar to a pointer, it is not a pointer. Each container is responsible for its own iterators. When a container is created, it has the ability to create an iterator that knows how to visit elements of the type stored in the container.
Now that we have these two great tools in the STL, we want to use them to solve problems. It turns out that many programming tasks fall into basic groups:
find
copy
sum
count
sort
These are all actions that we perform on sequences. The goal of the STL algorithms is to define these actions in a generic way. The STL algorithms satisfy this goal using small, reusable functions that avoid writing repetitive code and define a consistent, portable interface.
The abstractions in the STL are primarily concerned with performing actions on data stored in STL containers. Consider that counting elements in a list is not very different from counting elements in a vector.
17.1.1. STL Algorithms at a glance¶
The STL algorithms are part of the ISO C++ Standard. Currently, it contains more than 150 algorithms for searching, counting, and manipulating ranges. C++17 alone added 69 more algorithms to the library. While most of these (but not all) were new overloads to existing algorithms, it does demonstrate the dynamic nature of the STL and its growth.
The algorithms are organized into broad categories:
Algorithm operations |
Example algorithms |
---|---|
Non-modifying sequence operations |
|
Modifying sequence operations |
|
Partitioning operations |
|
Sorting operations |
|
Binary search operations |
|
Set operations |
|
Heap operations |
|
Min/max operations |
max, min, max_element, clamp |
Comparison operations |
|
Permutation operations |
|
Numeric operations |
|
Uninitialized memory operations |
Notice that only a single category of algorithms is considered ‘numeric’. In C++11, only 5 algorithms specifically do numeric computations. C++17 adds 6 more.
17.1.2. STL algorithms and loops¶
Most STL algorithms are essentially wrappers around loops. They often take a range of elements and an operation that is performed on each element. Structurally, this makes them similar to loops.
Most tasks you’ve written so far could be rewritten using algorithms.
One way to think about STL algorithms is to consider them named loops. That is, a loop that is important and general enough to justify getting named and encapsulated in its own function.
iota is a STL algorithm that fills a range [first, last)
with sequentially increasing values.
This is the sort of algorithm that occurs often enough that it was decided
to include it in the standard library
(but not until C++11).
The parameter value
defines the start value.
This value is assigned to first
,
and both first
and value
are incremented.
1template<typename ForwardIterator, typename T>
2void iota(ForwardIterator first,
3 ForwardIterator last, T value) {
4 while(first != last) {
5 *first++ = value;
6 ++value;
7 }
8}
Note the order of operations on 5.
First
first
is dereferenced andvalue
is assigned.Then the iterator is incremented.
See this example running step-by-step
Why prefer algorithms to hand-written loops?
Efficiency, for one.
Algorithms are often more efficient than the loops programmers produce. The developers of the STL have had overt 20 years to consider how to make these algorithms efficient. Many algorithms have code to handle specific edge cases your initial implementations might overlook.
Correctness
Writing loops is more subject to errors than algorithm calls. As a programmer you have to worry about initializing the loop, incrementing the loop, terminating the loop as well as the loop body.
When calling an algorithm, you only need to get the start and end iterators correct.
Often you don’t even need to care about the body - the algorithm takes care of all the details for you. Sometimes a lambda or function pointer is expected.
The STL implementations have been carefully reviewed and tested in many thousands of programs. It is safe to say that any STL algorithm has been tested more thoroughly than any comparable code you write yourself.
Maintainability
Algorithm calls result in clearer code. The STL is designed around a simple consistent set of interfaces. The more you use these interfaces, the more consistently your own code will be structured.
When combined together, algorithms can eliminate lots of code you other wise would have needed to write and results in more straightforward than the corresponding explicit loops.
Code you use from the STL is code you don’t need to maintain. The less code you have to maintain, the cheaper and easier it is to maintain.
More to Explore
From cppreference.com
Overview of the algorithms library
std::find (and find_if), std::count_if