Search code examples
c++performanceloopscalliteration

Would this code fetch the elements every iteration?


Normally, I would write code like that.

auto elements = get_elements();
for(auto i : elements)
{
    // ...
}

I wonder if I it would make any performance difference to use the code below instead. Would get_elements() get called every iteration or just once?

for(auto i : get_elements())
{
    // ...
}

Moreover, how about traditional for loops? If I don't modify the elements I loop over, would the compiler optimize that code to not call get_elements() every iteration?

for(auto i = get_elements().begin(); i != get_elements().end(); ++i)
{
    // ...
}

Solution

  • I wonder if I it would make any performance difference to use the code below instead

    As always, when it comes to performance, you should back up your assumptions with measurements.

    No other proof than clear measurements indicating that you have a bottleneck in that particular routine should be a reason for abandoning a clearer, simpler design in favor of a more complex, less intuitive one. That would be, by definition, premature optimization.

    Therefore, choose the form that best communicates its intent for you. This said, I can answer the following question:

    Would get_elements() get called every iteration or just once?

    No, it would get called only once. This behavior is mandated by paragraph 6.5.4/1 of the C++11 Standard:

    For a range-based for statement of the form

    for ( for-range-declaration : expression ) statement
    

    let range-init be equivalent to the expression surrounded by parentheses

    ( expression )
    

    [...] a range-based for statement is equivalent to

    {
        auto && __range = range-init; // <== HERE IS YOUR get_elements()!
        for ( auto __begin = begin-expr,
            __end = end-expr;    
            __begin != __end;
            ++__begin ) {
                for-range-declaration = *__begin;
                statement
            }
        }
    

    Regarding your second question:

    Moreover, how about traditional for loops?

    Those are just less clear about the purpose of the loop itself, and more error-prone. I would suggest avoiding manual loops.

    For instance, just by looking at its first line, it is evident that the purpose of a range-based for loop is to iterate through all the elements of a collection.

    The same is not evident for a manually unrolled for loop, where just by looking at the first line, you do not know whether the i variable will be incremented or manipulated anyhow inside the loop.

    This is nicely discussed in this article by Herb Sutter (see the solution to Question 2-a).