...

/

Use of Standard Algorithms Over Raw for-loops

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:

Press + to interact
// Original version using a for-loop
auto 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 ...