I recently became interested in the question of which of the various methods of passage through the collection are the most effective and productive, and in general when and in what situation is it better to use one or another method? We take std :: vector as a basis.

... std::vector<std::string> cities; std::string rostov = "Ростов"; std::string omsk = "Омск"; cities.push_back(rostov); cities.push_back(omsk); ... 

1 Method - the most primitive

 for (size_t i = 0; i < cities.size(); i++) { std::cout << cities.at(i) << std::endl; } 

2 Method - range for

 for (const auto& city : cities) { std::cout << city << std::endl; } 

3 Method - iterators

 for (auto it = cities.begin(); it != cities.end(); it++) { std::cout << *it << std::endl; } 

4 Method - lambda

 std::for_each(cities.begin(), cities.end(), [] (std::string &city) { std::cout << city << std::endl; }); 

For example, a vector with two elements was given, I would like to talk about a large volume of containers. And I would also like to hear about which of the options is better and why, if the body of the cycle does not just output its elements (one could do so std :: copy (...)), but perform some kind of calculation over the elements . Thank you in advance...

  • one
    to perform any kind of calculations on the elements - and here in more detail. IMHO, you need to divide the question into two: pass through the collection with the change and without changing elements. - Alexander Petrov
  • Just the same passage through the collection with changes and without changes, in order to understand what is better intended for. As well as a large collection volume and small ... - QuickDzen
  • one
    The vector is a very special collection, and not indicative, because it allows efficient access by index. And you "took it as a basis" ... - AnT
  • 2
    A worthwhile optimizing compiler will generate identical code for all four cases ... But if you can use C ++ 11, then I would consider the second method preferable because of its sweetness ... otherwise - the third ... - Fat-Zer

1 answer 1

In the first method, access to the element with the check ( cities.at(i) ) is unnecessary, since in the loop you have excluded going beyond the boundaries. You just need to display cities[i] , then it will be effective.

It is more effective not to store unnecessary objects initially:

 std::vector<std::string> cities; cities.push_back("Ростов"); cities.push_back("Омск"); 

The second option is also effective as the following option:

 copy(cities.begin(), cities.end(), std::ostream_iterator<std::string>(std::cout, " ")); 

The worst option is the fourth, because std::for_each every time it calls a lambda and returns it, which you basically do not need. And if you are trying to use the std::for_each, then first consider whether there is a more specialized algorithm like the one I gave?

  • one
    " std::for_each every time it calls lambda and returns it, which you don’t need in principle" - what does this mean? - AnT
  • one
    @AnT, you yourself understand perfectly what I meant. If I have poorly stated, then just correct. - AR Hovsepyan
  • one
    I honestly do not understand what you mean. That's it, "returns it" - what is "her"? Lambda? But lambda here no one "every time" returns. - AnT
  • one
    @AnT, the return value of the algorithm is a copy of the function object after it is applied to all elements in the range. - AR Hovsepyan
  • one
    So I misunderstood you. I thought that by "every time" you meant "at each iteration." Since there is no “lambda return” at each iteration, there is no sense in considering this problem: this lambda is an empty object and its one-time (per cycle) return will not affect efficiency. - AnT pm