Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing different types of C++ for-loops [closed]

C++ is very flexible, and I want to understand for-loop operations more deeply. I'm hoping for a good comparison of each implementation and what is better/faster/more efficient. Additionally, it would be a perk to learn some other way of implementing a for-loop - and not necessarily something in the STL.

I'm looking for expert answers, not opinions. Notice the many limitations I've put on answers: answers pertain only to the specific for-loops mentioned, their limitations (which may not be intuitive), specific alternatives not in the STL, and specific enhancements.

How do these other for-loops (not the 'traditional') work differently/better?

What are the limitations of the other 'non-traditional' for-loops?

Example 1) Traditional for-loop is:

for(int i=0;i<SIZE;i++){
    //do something for each iteration;
}

Example 2) Now lets say I have a vector of scores.

vector<int> scores = {77,91,100,88,85,68,95};

for (auto it = scores.begin(); it != scores.end(); ++it){
    //do something for each iteration;
}

Example 3) Same scores vector, different loop.

for (auto& x: scores) //do something for each iteration;

I'm particularly interested in example 3, because it is so simple, I'm not sure what it's actually doing, yet functionally is the same as the other two.

like image 661
NonCreature0714 Avatar asked Dec 02 '22 15:12

NonCreature0714


2 Answers

  1. You have access to i that you can use to figure out whether you're in the first, last or some other iteration. Not usable with non-random-access containers, so not an option for generic code that must work with vectors and lists alike. Supported since the first version of c++ standard.

  2. Works with all standard iterators and therefore appropriate for generic code. No access to iteration counter, but the count can be calculated with std::distance, however, if the iterator is not random access, then that adds up the complexity of iteration. Figuring out if you are in first or last iteration is still constant time, though. Supported since the first version of c++ standard.

  3. Much nicer syntax, but semantically equivalent to certain forms of 2. Sub-ranges can not be used: goes always from begin to end (unless you break out). No way to access iteration counter. Did not exist prior to c++11. There also exists macro based implementations such as BOOST_FOREACH that do a similar thing and support the older standard.

Iterator ranges can be used with the range-based for loop to get around this. They're not part of the standard library, but there are third party implementations.


TL;DR

  1. Handy when you need the iterator count and don't need generic code.
  2. For generic pre c++11 code.
  3. A good choice by default due to its simplicity.
like image 68
eerorika Avatar answered Dec 17 '22 07:12

eerorika


Version 3 is basically a short hand way of saying Version 2.

The item on the right scores must support std::begin(scores) and std::end(scores) and becomes syntactically equivalent too:

  for (auto& x: scores)
  {
      // STUFF
  }

  // Is the same as:

  for(auto tmp = std::begin(scores); tmp != std::end(scores); ++tmp)
  {
      auto& x = *tmp;
      // tmp not technically available.
      // STUFF
  }
like image 26
Martin York Avatar answered Dec 17 '22 05:12

Martin York