Is there a difference between the two for a form in C ++?

vector<int> a; 

1.

 for(vector<int>::iterator it = a.begin(); it != a.end(); ++it) 

2.

 vector<int>::iterator end = a.end(); for(vector<int>::iterator it = a.begin(); it != end; ++it) 

which is more effective? or the same?

+6
source share
4 answers

Initial criticism:

1 / Typical textbook example

 for(vector<int>::iterator it = a.begin(); it != a.end(); ++it) 

There is no magic, but the question arises: is there a ever changed in a loop that the boundary of the end can change?

2 / Improved

 vector<int>::iterator end = a.end(); for(vector<int>::iterator it = a.begin(); it != end; ++it) 

a.end() is executed only once. However, since end not const , it can be changed inside the loop.

In addition, it enters the identifier end in the outer region, polluting it.

Thus, there is a potential gain in performance, but not so much in clarity. In addition, it is much more detailed.


I would suggest several other ways:

3 / Best Guide

 for(vector<int>::iterator it = a.begin(), end = a.end(); it != end; ++it) 

It combines the advantages of v1 (fairly short-term, without external coverage) and v2 (performance), but it is not yet clear when end ever modified inside the loop body.

4 / Boost-powered

 BOOST_FOREACH(int& i, a) 

Even shorter than v1 , immediately identified at a glance, the absence of external space leakage and the guarantee of complete iteration (it is impossible to change the boundaries).

Unfortunately:

  • there are problems with commas in the type of the variable (because it depends on the preprocessor)
  • compile-time errors are completely cryptic (since they depend on the preprocessor)

Note: theoretically, the std::foreach algorithm could be made here, but to be honest ... too much effort in determining the predicate from the outside violates the locality of the code.

5 / C ++ 11 range operator for

 for (int& i: a) 

All advantages:

  • Extremely difficult
  • As best as C ++ hand-written loop
  • Guaranteed full iteration, no questions.

And none of the problems (area leakage, preprocessor magic).


Personally, I use the C ++ 11 range when I can (projects for a hobby) and BOOST_FOREACH differently (at work).

I avoid, like the plague, changing the container in which I repeat, preferring to rely on STL algorithms when I need to filter / delete elements ... It is too easy to spoil the boundary conditions and the iterator invalidity otherwise.

+10
source

2nd is more efficient since only the creation of the final iterator is required.

A smart compiler can optimize the first to be the second, but you cannot guarantee that this will happen.

In fact, this will be a bit of a difficult optimization, because the compiler must be 100% sure that any subsequent call to end () will not have any additional effects or return something else. Basically, he needs to know that at least during the cycle end () always returns something such that end () == previous call to end (). Regardless of whether compilers are executed, this optimization is not guaranteed.

+6
source

The second method is obviously better since it calls a.end () only once. In essence, if there are N nodes in your tree, you save N calls to a.end () .

+1
source

I think the first for loop is more defined. If you insert / delete elements inside a for loop, then the end tag that you defined is invalid. For instance:

 vector<int>::iterator mend = int_vec.end(), mbegin = int_vec.begin(); while(mbegin != mend) { cout << *mbegin << " "; int_vec.erase(mbegin); // mbegin is automatically invalidated // execution of this program causes bizarre runtime_error ! // never try this at home ! } 

A safer version of the above code could be the following:

 vector<int>::iterator mend = int_vec.end(), mbegin = int_vec.begin(); while(mbegin != mend) { cout << *mbegin << " "; int_vec.erase(mbegin); mbegin = int_vec.begin(); // ok, mbegin updated. } 
0
source

Source: https://habr.com/ru/post/914301/


All Articles