Using Standard-Library Algorithms in C++
Standard-library algorithms tend to be more carefully designed, specified, and implemented than the average hand-crafted loop.
A Loop Most Programs Have Written
Almost every C++ program eventually needs to do something to a collection of values. It might add the values up, search for one of them, or rearrange them. You can write a loop by hand for each of these jobs using only the bare features of the language. The C++ standard library, however, already provides ready-made algorithms for many of these jobs. This article answers a practical question: when both options are available, which one should you use, and why?
The short answer is that the guidance favors the standard-library algorithm. Standard-library algorithms tend to be more carefully designed, specified, and implemented than the average hand-crafted loop. Along the way you will trace exactly what happens inside both versions, so the preference becomes something you can check for yourself rather than something you simply accept.
Tracing a Hand-Written Summing Loop
Consider a simple task: add up the numbers stored in a vector. The hand-written approach uses an index-based loop to visit each element in turn. It starts a running total at zero and adds each value to that total. Read the program below and follow the loop mechanics before moving on.
14- The vector holds five values, indexed 0 through 4.
- total starts at zero and is the running total.
- The loop condition i <
v.size()decides when the loop stops. - total += v[i] adds the current element to the running total.
Tracing the running total one element at a time
Trace the hand-written loop over the vector {3, 1, 4, 1, 5} and record the value of total after each addition.
- 1Start
total is 0 and i is 0 before the first pass through the loop.
- 2Index 0
v[0] is 3, so total becomes 0 + 3 = 3.
- 3Index 1
v[1] is 1, so total becomes 3 + 1 = 4.
- 4Index 2
v[2] is 4, so total becomes 4 + 4 = 8.
- 5Index 3
v[3] is 1, so total becomes 8 + 1 = 9.
- 6Index 4
v[4] is 5, so total becomes 9 + 5 = 14.
- 7Stop
i becomes 5, which is no longer less than
v.size(), so the loop ends with total equal to 14.
The loop prints 14.
Handing the Loop to an Algorithm
Both versions compute the same total. The second version hands the repetitive work to a standard-library algorithm, here std::accumulate from the numeric header. You do not have to re-verify the loop mechanics each time you read the code, because the algorithm has already been designed, specified, and implemented with care.
What do you think happens?
Before reading the full program, predict what it prints.
Reveal answer
14
The values 3, 1, 4, 1, and 5 add up to 14, exactly as the hand-written loop computed.
14v.begin()andv.end()mark the range the algorithm works on.- The 0 is the starting value of the running total.
- No index variable, bounds check, or increment appears in the program.
Comparing What Each Version Asks You to Read
The two programs print the same result, but they differ in how much code a reader must mentally execute. In the hand-written version you read the index variable, the loop condition, the increment, and the accumulation step, then confirm they combine correctly. In the algorithm version those steps are still performed, but they are hidden inside the library call. The reader only has to recognize that the call sums the range from begin to end.
The Range an Algorithm Operates On
An algorithm does not usually receive the container itself. It receives a pair of iterators that describe a range. The first iterator, begin, refers to the first element to be processed. The second iterator, end, refers to one position past the last element. The range therefore includes begin and everything up to, but not including, end. This is why v.end() is not a valid element to read; it marks where processing stops.
The same pattern appears in other algorithms. A call such as std::sort(v.begin(), v.end()) rearranges the elements from begin up to but not including end. Because every standard-library algorithm works on a range in this way, once you learn the begin and end pattern you can read the call without re-deriving how far it reaches.
Container Algorithms as a Category
Container algorithms are a category of algorithms that operate on containers. The category is defined by the kind of thing the algorithm works on: a container of values, reached through iterators.
The relationship among these ideas is hierarchical. Standard-library algorithms form the broader family that the guidance recommends. Container algorithms are one category within that family. Three pieces take part in any container algorithm call: the container, which holds the data; the iterator pair, which describes the range; and the algorithm, which does the work. The container owns the values, while the algorithm borrows access to them through the iterators it is given.
Recognizing a Loop That Should Be Replaced
The guidance is to prefer standard-library algorithms over code written in the bare language. In practice, a hand-written loop is a strong candidate for replacement when it walks a whole collection or a clearly bounded range and performs one of the common jobs: adding values up, searching for a value, or rearranging elements. In the summing example, the loop had an index, a bounds condition, and an accumulation step, which are all the parts a library call is designed to absorb.
Search loops show the same pattern with a different control flow. A hand-written search loop checks a condition on each element, and it exits early when a match is found. The standard library offers algorithms such as std::find_if for this job. The condition checks, the advance from one element to the next, and the early exit all move inside the algorithm, and the call returns an iterator to the element it found. Your code keeps only the question it asks about each element.
Mistakes When Choosing Algorithms
Common mistake Treating end as the last element to process
What it looks likeWriting std::accumulate(v.begin(), v.end() - 1, 0) to sum all values and then wondering why the last value is missing.
Why it failsBecause the range includes begin and excludes end, end already marks the position past the last element. Subtracting one from it changes which values are included.
Do this insteadPass v.begin() and v.end() when the whole container should be processed, and use a different range only when you intentionally want to stop earlier.
Common mistake Assuming an algorithm is always a drop-in replacement
What it looks likeReplacing a loop that writes to a log each time it runs with a single algorithm call and expecting the log to still appear once per element.
Why it failsThe algorithm performs the job it was designed for. A side effect buried in a loop body is not automatically preserved when the work moves into a library call.
Do this insteadCheck that the algorithm performs the same job over the same range before replacing the loop, and keep the loop when the body does something the algorithm does not describe.
Common mistake Keeping an index-based loop out of habit when a range-based algorithm describes the job more clearly
Spotting Replaceable Loops
A loop walks a vector of prices and adds every price to a running sum, starting the sum at zero. Name the standard-library algorithm that could replace the loop, state the range it would take as arguments, and explain what work the reader no longer has to verify.
Hints
- Look at the job being done: it adds values up, and the library provides an algorithm for that job.
- The range is the whole container, so the arguments are the begin and end iterators of the vector.
- The reader no longer has to check the loop condition, the index, or the increment.
Explain in one or two sentences why a container algorithm is defined by the kind of thing it works on, and which piece of the call owns the data.
Hints
- Think about the three pieces: the algorithm, the iterator pair, and the container.
- Ask which piece holds the values and which piece only describes a range over them.
Key Points to Carry Forward
- 1Standard-library algorithms are preferred over hand-crafted loops written with only the bare features of the language, because they tend to be more carefully designed, specified, and implemented.
- 2The algorithm version of a summing task computes the same result as the index-based loop while hiding the index, condition, and increment inside the library call.
- 3An algorithm works on a range described by begin and end, which includes begin and stops just before end.
- 4Container algorithms are the category of algorithms that operate on containers, with the container owning the data and the iterator pair describing the range.
Key Takeaways
- Standard-library algorithms tend to be more carefully designed, specified, and implemented than the average hand-crafted loop, so they are preferred over code written in the bare language.
- A summing loop with an index, a condition, and an accumulation step can be replaced by a single algorithm call that produces the same result.
- Algorithms operate on a range given by begin and end, where begin is included and end marks the position past the last element.
- Container algorithms are a category of algorithms defined by the kind of thing they operate on: containers, reached through iterators.