0

What would be best, range-based for loop?

for (auto& i : just_a_vec )

Or an iterator for loop?

for (std::vector<std::string>::iterator it = just_a_vec.begin(); it < just_a_vec.end(); it++)
apetrai
  • 19
  • 6
  • Does this answer your question? [Why use iterators instead of array indices?](https://stackoverflow.com/questions/131241/why-use-iterators-instead-of-array-indices) – Philipp Oct 25 '21 at 19:54
  • 7
    @Philipp A range-based `for` is syntactic sugar on top of iterators, there is no such performance caveat. – Frank Oct 25 '21 at 19:56
  • 2
    What ever is most readable and invites fewest mistakes. – Galik Oct 25 '21 at 20:05
  • And deviate from the easiest to read/hardest to get wrong only if profiling shows that it's a significant bottleneck. – user4581301 Oct 25 '21 at 20:07
  • look to `std::for_each()` also. supports parallelization where these two do not. – Алексей Неудачин Oct 25 '21 at 20:23
  • The range-based for loop has undefined behaviour if the loop body invalidates the containers iterators AND that cannot be corrected in the loop body since there is no access to any of the container's iterators. Such cases can be corrected in the second form (e.g. after an operation that invalidates `it`, set `it` to be a valid iterator) - albeit still has undefined behaviour if iterators are used after being invalidated. There are numerous questions here about cases where using a vector's `erase()` member function in a range-based for loop produces unexpected results. – Peter Oct 26 '21 at 02:23

2 Answers2

5

Iterators predate range-based for loops, so they used to be the only of these two alternatives available. Nowadays, range-based for has mostly replaced iterators when dealing with a simple loop.

However, iterators can be used in various other contexts as well. For example, you can do std::sort(v.begin(), std::next(v.begin(), 5)) to sort the first five elements of a vector while leaving the rest of it alone.

Going back to iterating over a whole container:

  • If you can accomplish what you want with a range-based for, then it leads to more legible code, so they are preferable by default.

  • If you need iterators for some reason, such as using an algorithm that requires them, or because you need to jump ahead or back while iterating, then use those instead.

Also: In the later case, you can/should still use auto when declaring the iterator:

for(auto it = just_a_vec.begin(); it < just_a_vec.end(); it++) {
}

Edit: as asked: here's a simple, if a bit contrived, example where an iterator-based loop can still be useful:

// adds all values in the vector, but skips over twos values when encountering a 0
// e.g.: {1,2,0,4,5,2} => 5
int my_weird_accum(const std::vector<int>& data) {
  int result = 0; 
 
  for(auto it = data.begin(); it != data.end(); ++it) {
    auto v = *it;
    result += v;

    if(v == 0) {
      // skip over the next two
      assert(std::distance(it, data.end()) > 2);
      std::advance(it, 2);
    }
  }
  return 0;
}
Frank
  • 18,728
  • 1
  • 23
  • 49
3

Quick personal answer: Its somewhat sylistic and based on what version of c++ you are using. I typically prefer range based, but there are certainly moments iterators shine as well. Add both to your toolchest. For further reading.

Here is a list of other SO answers that get more into the performance and use cases.

For further information. Google

Range vs iterator loop c++

Frebreeze
  • 212
  • 2
  • 9
  • Yes this is very helpful! I also heard that it helps with unorderd maps? Or something like that. – apetrai Oct 25 '21 at 19:59