Use Range Based For Loops – EasyHack

Because for loops are a powerful tool in C/C++, they are one of the desirable tools when you want to do something repeatedly, or process elements of a data structures. But there many ways to write a for loop. Some forms of it are easier to use, read, write and understand, and some are not. Range based for loops are discussed in this article. They can be good if you know where to use them.

Range Based For Loops

Since C++11, range based for loops are available to iterate over a known
range of values. For example, when there is a need to process elements
of a container, range based loops are usually a good choice. They are
easy to write, read and understand.

The simplest form is as below, but be warned that it is not usually good:

for(auto variable : range)

In this way, a temporary variable is created to iterate over the range of values. But this is usually undesirable, because the a copy of the variable is created each time.

When you need to modify the values of the elements, you should use a reference:

for(auto &variable : range)

This is also useful for working on big elements, as it can speed up the code by avoiding unneeded copying.

Const Reference

If modifying the elements is not needed, it is possible to use the reference, but use const to prevent modification of the referenced object. This is an example:

for(auto const &element : range)

This is usually called east const. The latter is semantically equivalence, but is called west const:

for(const auto &element : range)

The reference element itself can not be changed, and that is also true for references to non-pointer objects.

There are other variants that are discussed in Auto Type Deduction in Range-Based For Loops.

Declaring Variable Type

You can use auto to let C++ compiler decide the suitable type for the loop variable, but you can also declare the variable type explicitly instead of using auto. Both of them are acceptable.

For a good example, see this commit from Michael Weghorn:

Sequence pStates = pRState->getStates();
int count = pStates.getLength();
for( int iIndex = 0;iIndex < count;iIndex++ )
    if (pStates[iIndex] == AccessibleStateType::MANAGES_DESCENDANTS)
        return true;

is converted into this range based for loop:

for (sal_Int16 nState : pRState->getStates())
    if (nState == AccessibleStateType::MANAGES_DESCENDANTS)
        return true;

Limitations of Range Based For Loops

Range based loops can simplify the code, but there are limitations for them. For example, if there is a need not to skip certain values, you will need std::ranges::views::drop which is available in C++20. Thus, they are not suitable for replacing every normal for loop.

For an initialization statement in the range based for loop, you will also need C++20.

Final Notes

EasyHacks are a good start for newcomers. This specific improvement is filed as tdf#145538.

You can find some possible candidates for changing to range based for loops with these commands:

$ git grep -w for *.cxx | grep -iF "size()"
$ git grep -w for *.cxx | grep -iF "length()"

Good candidates can be found among the results.

If you want to contribute to LibreOffice code by working on this improvement, but you need to know how to get started with LibreOffice development, I suggest you to see our video tutorial:

Getting Started (Video Tutorial)