Use of Standard Algorithms Over Raw for-loops
Learn to use standard algorithms for efficient problem-solving.
Efficient problem solving with standard algorithms
It’s easy to forget that complex algorithms can be implemented by combining algorithms from the standard library. Maybe because of our old habit of trying
to solve problems by hand and immediately starting to handcraft for-
loops and working through the problem using an imperative approach. If this sounds familiar, we recommend getting to know the standard algorithms well enough so that by starting considering them as the first choice.
We promote the use of standard library algorithms over raw for
-loops for a number of reasons:
- Standard algorithms deliver performance. Even though some of the algorithms in the standard library may seem trivial, they are often optimally designed in ways that are not obvious at first glance.
- Standard algorithms provide safety. Even simpler algorithms may have corner cases, which are easy to overlook.
- Standard algorithms are future-proof; a more suitable algorithm can replace a given algorithm if we want to take advantage of SIMD extensions, parallelism, or even the GPU.
- Standard algorithms are thoroughly documented.
In addition, by using algorithms instead of for
-loops, the intention of each operation is clearly indicated by the algorithm’s name. The readers of the code do not need to inspect details inside the raw for
-loop to determine what the code does if uses standard algorithms as building blocks.
Once we get into the habit of thinking in terms of algorithms, we’ll realize that many for
-loops are most often a variation of a few simple algorithms such as std::transform()
, std::any_of()
, std::copy_if()
, and std::find()
.
Using algorithms will also make the code cleaner. We can often implement functions without nested code blocks and, at the same time, avoid mutable variables. This will be demonstrated in the following example.
Example 1: Readability issues and mutable variables
Our first example is from a real-world code base, although variable names have been disguised. As it is only a cut-out, we don’t have to understand the logic of the code. The example here shows how the complexity is lowered when using algorithms compared to nested for
-loops.
The original version looked like this:
// Original version using a for-loopauto conflicting = false;for (const auto& info : infos) {if (info.params() == output.params()) {if (varies(info.flags())) {conflicting = true;break;}}else {conflicting = true;break;}}
In the for
-loop version, it’s hard to grasp when or why conflicting
is set to true
, whereas in the following versions of the algorithm, we can instinctively see that it happens if info fulfills a predicate. Further, the standard algorithm version uses no ...