Published in July of 2018, he does a 256 page whirlwind tour of C++, concentrating on C++17 (the current standard), and including some forward looking material for C++20 (draft). Much is backward compatible with the C++11 and C++14 standards and before. It is part of the The C++ In-Depth Series, whose authors were chosen by Stroustrup.
Range Based for Loop
This first post explores the first thing he discussed that really caught my attention about C++—the range based
for loop (range-for-statement). When it can be
used appropriately for simple needs, it is much more succinct and less error prone than the original ANSI C style
for statement. It was added to the standard
C++11 back in 2011.
Standard for Statement
The only option in ANSI C, or C++ before C++11, was the standard
Notice the programming steps we must take above. First, we simultaneously declare, set the number of elements of, and initialize the integer array that holds
the values we want to print. Then, for the standard
for statement, we must do all the following steps:
- Get the size of the entire array using
- Get the size of each array element using
- Calculate the number of elements by dividing the size of the array by the size of each element.
- Declare an index variable.
- Initialize the index variable to zero to point to the first element in the zero index based array.
- Include a conditional expression to stop the looping when the index value reaches the correct upper limit using the previously calculated number of elements.
- Explicitly define the correct index increment statement.
- Use the index variable inside the
operator on the array variable each iteration to get the appropriate value.
That is a lot we must do to print out a simple list of integer values. Even though it is compact, the (relatively) error-prone programmer must do a lot of steps for such a simple thing. Forgot to initialize the index variable? Used commas instead of semicolons in the for statement? Calculated the number of elements wrong? Used the wrong comparison operator in the conditional expression? See generalized diagram below:
What the code in the
for loop actually accomplishes even sounds complex when written out: “Initialize the index variable
ii to zero. For each iteration,
check if the index variable is still less than the number of elements. If not, we’re done. If so, print out the appropriate value of the array element
for the current loop iteration pointed to by the index variable, then increment the index variable and repeat.”
Range to the Rescue!
Compare the above code and steps with the code and steps below which accomplishes the same thing using the range-for-statement:
As above, we simultaneously declare and initialize the array, then in the range-for-statement we:
- Declare an appropriate variable left of the colon (the range_declaration) to receive the desired value each iteration.
- Include the range_expression to the right of the colon to define the variable from which the values will be read.
- Directly use the variable declared to the left of the colon in the body of the range-for-statement in our print statement.
The number of steps the programmer must do himself is reduced from 8 to 3, and all the low-level, error prone complexity is now being handled automatically by the compiler, presumably error free.
What this code actually does is the following (quoting from Stroustrup, with appropriate changes): “For every element of
intAry, from the first
to the last, place a copy in
xx and print it.” See generalized diagram below:
The compiler can automatically determine how to read and write sequentially from the type signatures of the range_declaration and range_expression.
With the the
auto type used in the range_declaration to declare the receptor variable
xx, the compiler takes care of picking the appropriate type
for it based on the range_expression type.
It Gets Even Better
Stroustrup shows how you can shrink this code down even further by including the list of array values as an expression directly in the range-for-statement:
We are now down to just two source lines of code to do this task. The range_expression is now the same as the initializer expression used in the previous code to set the number of elements in the array and initialize their values.
And Even Better
So far, we have just done a very simple thing—print out a sequence of unchanging integer values from an array. Stroustrup shows how to work a little magic with reference types to increment each value in the array, all very succinctly and with few chances for error:
In the first range-for-statement above, we declare a reference variable using the reference unary suffix operator
&. Instead of copying the value of each
successive integer in the array into
xx, when a reference variable is declared, the compiler points the reference variable to the location of each
successive integer in the array.
In the statement body, when we increment the reference variable, it actually increments the integer value in the original location that the reference
variable points to, which is an element in the original array
intAry. Here is a diagram that shows this graphically:
The second range-for-statement just prints out the new values in the array to show that they were indeed incremented (going now from 1 to 10 instead of from 0 to 9).
The range-for-statement is an easy to use, welcome addition to C++. Not only does it make the programming less protracted and error prone, it is easier to read and understand.
This series on A Tour of C++ should be a very good one, as the book is excellent and up-to-date, showing many features of C++17 and C++20 to explore and learn. Stay tuned for more as I get excited about new features in C++, or find new and better ways to use old ones, and explore them here with you.