Foreach range iteration over a vector<int> - auto or auto&?

12,670

Solution 1

Before caring about which is faster, you should care about which is semantically correct. If you do not need to alter the element being iterated, you should choose the first version. Otherwise, you should choose the second version.

Sure, you could object that even if you do not need to alter the content of the vector, there is still the option to use a reference to const:

 for(auto const& value : ints)

And then the question becomes: Which is faster? By reference to const or by value?

Well, again, you should first consider whether the above is semantically correct at all, and that depends on what you are doing inside the for loop:

int i = 0;
for (auto const& x : v) // Is this correct? Depends! (see the loop body)
{
    v[i] = 42 + (++i);
    std::cout << x;
}

This said, for fundamental types I would go with for (auto i : x) whenever this is semantically correct.

I do not expect performance to be worse (rather, I expect it to be better), but as always when it comes to performance, the only meaningful way to back up your assumptions is to measure, measure, and measure.

Solution 2

If you modify value and expect it to modify an actual element in the vector you need auto&. If you don't modify value it likely compiles into the exact same code with auto or auto& (profile it to find out for yourself).

I did some timing using VS2012 with a timer based on QueryPerformanceCounter...

    m::HighResTimer timer;

    std::vector<int> ints(100000000, 17);

    int count = 0;

    timer.Start();
    for(auto& i : ints)
        count += i;
    timer.Stop();

    std::cout   << "Count: " << count << '\n'
                << "auto& time: " << duration_cast<duration<double, std::milli>>(timer.Elapsed()).count() << '\n';

    count = 0;
    timer.Reset();
    timer.Start();
    for(const auto& i : ints)
        count += i;
    timer.Stop();

    std::cout   << "Count: " << count << '\n'
                << "const auto& time: " << duration_cast<duration<double, std::milli>>(timer.Elapsed()).count() << '\n';

    count = 0;
    timer.Reset();
    timer.Start();
    for(auto i : ints)
        count += i;
    timer.Stop();

    std::cout   << "Count: " << count << '\n'
                << "auto time: " << duration_cast<duration<double, std::milli>>(timer.Elapsed()).count() << '\n';

The Results....

Count: 1700000000
auto& time: 77.0204

Count: 1700000000
const auto& time: 77.0648

Count: 1700000000
auto time: 77.5819
Press any key to continue . . .

I wouldn't read into the time differences here. For all practical purposes they are identical, and fluctuate slightly run to run.

Solution 3

First of all, if you going to modify value use auto&, if not - don't. Because you can accidentally change it.

But there may be choice between const auto& and simple auto. I believe that performance isn't issue here, for std::vector<int>.

Why use auto

  1. It's easier to read.
  2. It's allow to change it(without changing vector)

Why use const auto&

  1. It should be used with other type, so it's more generic to write this way. Moreover, if you change type to any complicated type, you will not accidentally get performance issues.
  2. It doesn't allow to change value of this variable, so some errors maybe catched in compilation time.

In both cases you should understand what do you do. It may depend if the cycle somehow modify our range.

Solution 4

In GCC, both versions compile to the same assembly with optimization flags -O1 through -O3.

Since the compiler takes care of the optimization for you, I would use the for (auto value : ints) whenever you don't need to change the value. As Andy points out, you could use const-refs, but if there's no performance gain whatsoever, then I wouldn't bother.

Share:
12,670
Vittorio Romeo
Author by

Vittorio Romeo

I write code, lift weights and play games. I also like everything sci-fi.

Updated on June 07, 2022

Comments

  • Vittorio Romeo
    Vittorio Romeo almost 2 years

    Game engine micro-optimization situation: I'm using C++11 range for loop to iterate over a vector<int>, with the auto keyword.

    What is faster:

    for(auto value : ints) ...
    

    or

    for(auto& value : ints) ...
    

    ?