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 efficient?or the same?
Initial criticisms:
1/ Typical tutorial example
for(vector<int>::iterator it = a.begin(); it != a.end(); ++it)
There is no magic, but it brings up a question: is a ever modified in the loop that the end bound may vary ?
2/ Improved
vector<int>::iterator end = a.end();
for(vector<int>::iterator it = a.begin(); it != end; ++it)
a.end() is only executed once, it seems. However since end is not const, it may be modified inside the loop.
Furthermore, it introduces the end identifier in the outer scope, polluting it.
So there is a potential gain in performance, but not much in clarity. Also, it's far more verbose.
I would propose several other ways:
3/ Best Manual
for(vector<int>::iterator it = a.begin(), end = a.end(); it != end; ++it)
Combines the advantages of v1 (quite terse, no outer scope pollution) and v2 (performance), however it is still unclear if end is ever modified within the loop body.
4/ Boost-powered
BOOST_FOREACH(int& i, a)
Even terser than v1, immediately identifiable at a glance, no outer scope leak, and guarantee of full iteration (it's not possible to modify the bounds).
Unfortunately:
there are issues with commas in the type of the variable (because it relies on the preprocessor)
compile-time errors are completely cryptic (because it relies on the preprocessor)
Note: in theory, one could make the case of the std::foreach algorithm here, but honestly... there is too much effort involved in defining a predicate outside and it breaks code locality.
5/ C++11 range-for statement
for (int& i: a)
All the advantages:
Extremely Terse
As performant as the best C++ hand-written loop
Guaranteed full iteration, no questions asked
And none of the issues (scope leak, preprocessor magic).
Personally, I use C++11 range-for whenever I can (hobby projects) and BOOST_FOREACH otherwise (at work).
I avoid like the plague modifying the container I am iterating on, preferring to rely on STL algorithms when I need to filter/remove elements... It's too easy to mess up with the boundary conditions and iterator invalidations otherwise.
2nd is more efficient as it only requires creating the end iterator once.
A smart compiler may optimize the first one to be the second, but you cannot be guaranteed that that will happen.
It would actually be a bit of a complicated optimization because the compiler would need to be 100% certain that any subsequent call to end() will have no additional effects or return anything different. Basically, it would need to know that at least over the loop, end() always returns something such that end() == previous call to end(). Whether or not compilers do that optimization is not guaranteed.
2nd way is obviously better, as it calls a.end() only once. In essence if there are N nodes in your tree then you save N calls to a.end().
I think that the first for loop is more certain. In case you insert/erase elements inside this for loop the end iterator you have defined is invalidated. For example:
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 code above could be this:
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.
}
Related
In terms of space-time complexity which of the following is best way to iterate over a std::vector and why?
Way 1:
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
/* std::cout << *it; ... */
}
Way 2:
for(std::vector<int>::size_type i = 0; i != v.size(); i++) {
/* std::cout << v[i]; ... */
}
Way 3:
for(size_t i = 0; i != v.size(); i++) {
/* std::cout << v[i]; ... */
}
Way 4:
for(auto const& value: a) {
/* std::cout << value; ... */
First of all, Way 2 and Way 3 are identical in practically all standard library implementations.
Apart from that, the options you posted are almost equivalent. The only notable difference is that in Way 1 and Way 2/3, you rely on the compiler to optimize the call to v.end() and v.size() out. If that assumption is correct, there is no performance difference between the loops.
If it's not, Way 4 is the most efficient. Recall how a range based for loop expands to
{
auto && __range = range_expression ;
auto __begin = begin_expr ;
auto __end = end_expr ;
for ( ; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
The important part here is that this guarantees the end_expr to be evaluated only once. Also note that for the range based for loop to be the most efficient iteration, you must not change how the dereferencing of the iterator is handled, e.g.
for (auto value: a) { /* ... */ }
this copies each element of the vector into the loop variable value, which is likely to be slower than for (const auto& value : a), depending on the size of the elements in the vector.
Note that with the parallel algorithm facilities in C++17, you can also try out
#include <algorithm>
#include <execution>
std::for_each(std::par_unseq, a.cbegin(), a.cend(),
[](const auto& e) { /* do stuff... */ });
but whether this is faster than an ordinary loop depends on may circumstantial details.
Prefer iterators over indices/keys.
While for vector or array there should be no difference between either form1, it is a good habit to get into for other containers.
1 As long as you use [] instead of .at() for accesssing by index, of course.
Memorize the end-bound.
Recomputing the end-bound at each iteration is inefficient for two reasons:
In general: a local variable is not aliased, which is more optimizer-friendly.
On containers other than vector: computing the end/size could be a bit more expensive.
You can do so as a one-liner:
for (auto it = vec.begin(), end = vec.end(); it != end; ++it) { ... }
(This is an exception to the general prohibition on declaring a single variable at a time.)
Use the for-each loop form.
The for-each loop form will automatically:
Use iterators.
Memorize the end-bound.
Thus:
for (/*...*/ value : vec) { ... }
Take built-in types by values, other types by reference.
There is a non-obvious trade-off between taking an element by value and taking an element by reference:
Taking an element by reference avoids a copy, which can be an expensive operation.
Taking an element by value is more optimizer-friendly1.
At the extremes, the choice should be obvious:
Built-in types (int, std::int64_t, void*, ...) should be taken by value.
Potentially allocating types (std::string, ...) should be taken by reference.
In the middle, or when faced with generic code, I would recommend starting with references: it's better to avoid a performance cliff than attempting to squeeze out the last cycle.
Thus, the general form is:
for (auto& element : vec) { ... }
And if you are dealing with a built-in:
for (int element : vec) { ... }
1 This is a general principle of optimization, actually: local variables are friendlier than pointers/references because the optimizer knows all the potential aliases (or absence, thereof) of the local variable.
Addition to lubgr's answer:
Unless you discover via profiling the code in question to be a bottleneck, efficiency (which you probably meant instead of 'effectivity') shouldn't be your first concern, at least not on this level of code. Much more important are code readability and maintainability! So you should select the loop variant that reads best, which usually is way 4.
Indices can be useful if you have steps greater than 1 (whyever you would need to...):
for(size_t i = 0; i < v.size(); i += 2) { ... }
While += 2 per se is legal on iterators, too, you risk undefined behaviour at loop end if the vector has odd size because you increment past the one past the end position! (Generally spoken: If you increment by n, you get UB if size is not an exact multiple of n.) So you need additional code to catch this, while you don't with the index variant...
The lazy answer: The complexities are equivalent.
The time complexity of all solutions is Θ(n).
The space complexity of all solutions is Θ(1).
The constant factors involved in the various solutions are implementation details. If you need numbers, you're probably best off benchmarking the different solutions on your particular target system.
It may help to store v.size() rsp. v.end(), although these are usually inlined, so such optimizations may not be needed, or performed automatically.
Note that indexing (without memoizing v.size()) is the only way to correctly deal with a loop body that may add additional elements (using push_back()). However, most use cases do not need this extra flexibility.
Prefer method 4, std::for_each (if you really must), or method 5/6:
void method5(std::vector<float>& v) {
for(std::vector<float>::iterator it = v.begin(), e = v.end(); it != e; ++it) {
*it *= *it;
}
}
void method6(std::vector<float>& v) {
auto ptr = v.data();
for(std::size_t i = 0, n = v.size(); i != n; i++) {
ptr[i] *= ptr[i];
}
}
The first 3 methods can suffer from issues of pointer aliasing (as alluded to in previous answers), but are all equally bad. Given that it's possible another thread may be accessing the vector, most compilers will play it safe, and re-evaluate [] end() and size() in each iteration. This will prevent all SIMD optimisations.
You can see proof here:
https://godbolt.org/z/BchhmU
You'll notice that only 4/5/6 make use of the vmulps SIMD instructions, where as 1/2/3 only ever use the non-SIMD vmulss instructiuon.
Note: I'm using VC++ in the godbolt link because it demonstrates the problem nicely. The same problem does occur with gcc/clang, but it's not easy to demonstrate it with godbolt - you usually need to disassemble your DSO to see this happening.
For completeness, I wanted to mention that your loop might want to change the size of the vector.
std::vector<int> v = get_some_data();
for (std::size_t i=0; i<v.size(); ++i)
{
int x = some_function(v[i]);
if(x) v.push_back(x);
}
In such an example you have to use indices and you have to re-evaluate v.size() in every iteration.
If you do the same with a range-based for loop or with iterators, you might end up with undefined behavior since adding new elements to a vector might invalidate your iterators.
By the way, I prefer to use while-loops for such cases over for-loops but that's another story.
It depends to a large extent on what you mean by "effective".
Other answers have mentioned efficiency, but I'm going to focus on the (IMO) most important purpose of C++ code: to convey your intent to other programmers¹.
From this perspective, method 4 is clearly the most effective. Not just because there are fewer characters to read, but mainly because there's less cognitive load: we don't need to check whether the bounds or step size are unusual, whether the loop iteration variable (i or it) is used or modified anywhere else, whether there's a typo or copy/paste error such as for (auto i = 0u; i < v1.size(); ++i) { std::cout << v2[i]; }, or dozens of other possibilities.
Quick quiz: Given std::vector<int> v1, v2, v3;, how many of the following loops are correct?
for (auto it = v1.cbegin(); it != v1.end(); ++it)
{
std::cout << v1[i];
}
for (auto i = 0u; i < v2.size(); ++i)
{
std::cout << v1[i];
}
for (auto const i: v3)
{
std::cout << i;
}
Expressing the loop control as clearly as possible allows the developer's mind to hold more understanding of the high-level logic, rather than being cluttered with implementation details - after all, this is why we're using C++ in the first place!
¹ To be clear, when I'm writing code, I consider the most important "other programmer" to be Future Me, trying to understand, "Who wrote this rubbish?"...
All of the ways you listed have identical time complexity and identical space complexity (no surprise there).
Using the for(auto& value : v) syntax is marginally more efficient, because with the other methods, the compiler may re-load v.size() and v.end() from memory every time you do the test, whereas with for(auto& value : v) this never occurs (it only loads the begin() and end() iterators once).
We can observe a comparison of the assembly produced by each method here: https://godbolt.org/z/LnJF6p
On a somewhat funny note, the compiler implements method3 as a jmp instruction to method2.
The complexity is the same for all except the last one that is in theory faster because the end of the container is evaluated only once.
Last one is also the nicest to read and to write, but has the drawback that doesn't give you the index (that is quite often important).
You are however ignoring what I think is a good alternative (it's my preferred one when I need the index and cannot use for (auto& x : v) {...}):
for (int i=0,n=v.size(); i<n; i++) {
... use v[i] ...
}
note that I used int and not size_t and that the end is computed only once and also available in the body as a local variable.
Often when the index and the size are needed then math computations are also performed on them and size_t behaves "strangely" when used for math (for example a+1 < b and a < b-1 are different things).
This question already has answers here:
Incrementing iterators: Is ++it more efficient than it++? [duplicate]
(7 answers)
Closed 6 years ago.
Johannes Schaub claims here
always use the prefix increment form for iterators whose definitions
you don't know. That will ensure your code runs as generic as
possible.
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
/* std::cout << *it; ... */
}
Why doesn't this first iterate it, then start the loop (at v.begin() + 1)?
Why doesn't this first iterate it, then start the loop (at v.begin() + 1)?
The iteration statement is always executed at the end of each iteration. That is regardless of the type of increment operator you use, or whether you use an increment operator at all.
The result of the iteration statement expression is not used, so it has no effect on how the loop behaves. The statement:
++it;
Is functionally equivalent to the statement:
it++;
Postfix and prefix increment expressions have different behaviour only when the result of the expression is used.
Why use the prefix increment form for iterators?
Because the postfix operation implies a copy. Copying an iterator is generally at least as slow, but potentially slower than not copying an iterator.
A typical implementation of postfix increment:
iterator tmp(*this); // copy
++(*this); // prefix increment
return tmp; // return copy of the temporary
// (this copy can be elided by NRVO)
When the result is not used, even the first copy can be optimized away but only if the operation is expanded inline. But that is not guaranteed.
I wouldn't blindly use the rule "always use prefix increment with itrators". Some algorithms are clearer to express with postfix, although that is just my opinion. An example of an algorithm suitable for postfix increment:
template<class InIter, class OutIter>
OutIter copy(InIter first, InIter last, OutIter out) {
while(first != last)
*out++ = *first++;
return out;
}
Note that your code is equivalent to
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ) {
/* std::cout << *it; ... */
++it;
}
and it should be readily apparent that it doesn't matter if you write ++it; or it++;. (This also addresses your final point.)
But conceptually it++ needs to store, in its implementation, a copy of the unincremented value, as that is what the expression evaluates to.
it might be a big heavy object of which taking a value copy is computationally expensive, and your compiler might not be able to optimise away that implicit value copy taken by it++.
These days, for most containers, a compiler will optimise the arguably clearer it++ to ++it if the value of the expression is not used; i.e. the generated code will be identical.
I follow the author's advice and always use the pre-increment whenever possible, but I am (i) old fashioned and (ii) aware that plenty of expert programmers don't, so it's largely down to personal choice.
Why doesn't this first iterate it, then start the loop (at v.begin() + 1)?
Because the for loop will be parsed as:
{
init_statement
while ( condition ) {
statement
iteration_expression ;
}
}
So
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
/* std::cout << *it; ... */
}
is equivalent to
{
std::vector<T>::iterator it = v.begin();
while ( it != v.end() ) {
/* std::cout << *it; ... */
++it ;
}
}
That means it would do the loop at v.begin() at first, then step forward it. Prefix increment means increase the value and then return the reference of the increased object; As you can seen the returned object is not used at all for this case, then ++it and it++ will lead to the same result.
Sorry if this is too simple a question.
Prior error checking ensures l1.size() == l2.size().
std::list<object1>::iterator it1 = l1.begin();
std::list<object2>::iterator it2 = l2.begin();
while(it1 != l1.end() && it2 != l2.end()){
//run some code
it1++;
it2++;
}
Is this a reasonable approach, or is there a more elegant solution? Thanks for your help.
I prefer to use for if increments unconditionally occurs:
for(; it1 != l1.end() && it2 != l2.end(); ++it1, ++it2)
{
//run some code
}
You can omit one test while the size of lists are the same, but I'm not sure what's going on in run some code!
I think this is perfectly reasonable (except that I'd use pre-increment rather than post-increment).
You could consider using a "zip iterator" of some sort, but it's not totally obvious that this would be worth the hassle in this case.
If you are doing a simple operation on each pair of objects, you can use std::transform.
It is reasonable to do it the way you have, there are some other approaches you could take to minimise the amount of checks being done:
If you have already checked both lengths are equal (as stated as a prior check), a standard for loop may well suffice, which eliminates the access of two variables and relies only on the increment of one variable:
for (int i = 0; i< l1.size();i++)
{
// run some code here
}
However you would need to use advance() or next() to march through the objects in the list within the "some code here".
For a very simple thing, like for example to print each element in a vector, what is the better way to use in C++?
I have been using this:
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
before, but in one of the Boost::filesystem examples I have seen this way:
for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
For me it looks more complicated and I don't understand why is it better then the one I have been using.
Can you tell me why is this version better? Or it doesn't matter for simple things like printing elements of a vector?
Does i != values.end() make the iterating slower?
Or is it const_iterator vs iterator? Is const_iterator faster in a loop like this?
Foo x = y; and Foo x(y); are equivalent, so use whichever you prefer.
Hoisting the end out of the loop may or may not be something the compiler would do anyway, in any event, it makes it explicit that the container end isn't changing.
Use const-iterators if you aren't going to modify the elements, because that's what they mean.
for (MyVec::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
/* ... */
}
In C++0x, use auto+cbegin():
for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
(Perhaps you'd like to use a ready-made container pretty-printer?)
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
...vs...
for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
For me [the latter, seen in boost] looks more complicated and I don't understand why is it better then the one I have been using.
I'd say it would look more complicated to anybody who hasn't got some specific reason for liking the latter to the extent that it distorts perception. But let's move on to why it might be better....
Can you tell me why is this version better? Or it doesn't matter for simple things like printing elements of a vector?
Does i != values.end() make the iterating slower?
it_end
Performance: it_end gets the end() value just once as the start of the loop. For any container where calculating end() was vaguely expensive, calling it only once may save CPU time. For any halfway decent real-world C++ Standard library, all the end() functions perform no calculations and can be inlined for equivalent performance. In practice, unless there's some chance you may need to drop in a non-Standard container that's got a more expensive end() function, there's no benefit to explicitly "caching" end() in optimised code.This is interesting, as it means for vector that size() may require a small calculation - conceptually subtracting begin() from end() then dividing by sizeof(value_type) (compilers scale by size implicitly during pointer arithmetic), e.g. GCC 4.5.2:
size_type size() const
{ return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
Maintenance: if the code evolves to insert or erase elements inside the loop (obvious in such a way that the iterator itself isn't invalidated - plausible for maps / sets / lists etc.) it's one more point of maintenance (and hence error-proneness) if the cached end() value also needs to be explicitly recalculated.
A small detail, but here vec must be a typedef, and IMHO it's often best to use typedefs for containers as it loosens the coupling of container type with access to the iterator types.
type identifier(expr)
Style and documentary emphasis: type identifier(expr) is more directly indicative of a constructor call than type identifier = expr, which is the main reason some people prefer the form. I generally prefer the latter, as I like to emphasise the sense of assignment... it's visually unambiguous whereas function call notation is used for many things.
Near equivalence: For most classes, both invoke the same constructor anyway, but if type has an explicit constructor from the type of expr, it will be passed over if = is used. Worse still, some other conversion may allow a less ideal constructor be used instead. For example, X x = 3.14;, would pass over explicit X::X(double); to match X::X(int) - you could get a less precise (or just plain wrong) result - but I'm yet to be bitten by such an issue so it's pretty theoretical!
Or is it const_iterator vs iterator? Is const_iterator faster in a loop like this?
For Standard containers, const_iterator and iterator perform identically, but the latter implies you want the ability to modify the elements as you iterate. Using const_iterator documents that you don't intend to do that, and the compiler will catch any contradictory uses of the iterator that attempt modification. For example, you won't be able to accidentally increment the value the iterator addresses when you intend to increment the iterator itself.
Given C++0x has been mentioned in other answers - but only the incremental benefit of auto and cbegin/cend - there's also a new notation supported:
for (const Foo& foo: container)
// use foo...
To print the items in a vector, you shouldn't be using any of the above (at least IMO).
I'd recommend something like this:
std::copy(values.begin(), values.end(),
std::ostream_iterator<T>(std::cout, "\n"));
You could just access them by index
int main(int argc, char* argv[])
{
std::vector<int> test;
test.push_back(10);
test.push_back(11);
test.push_back(12);
for(int i = 0; i < test.size(); i++)
printf("%d\n", test[i]);
}
prints out:
10
11
12
I don't think it matters. Internally, they do the same thing, so you compiler should optimise it anyway. I would personally use the first version as I find it much clearer as it closely follows the for-loop strucutre.
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
Typically you will find STL code like this:
for (SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin(); Iter != m_SomeMemberContainerVar.end(); ++Iter)
{
}
But we actually have the recommendation to write it like this:
SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin();
SomeClass::SomeContainer::iterator IterEnd = m_SomeMemberContainerVar.end();
for (; Iter != IterEnd; ++Iter)
{
}
If you're worried about scoping, add enclosing braces:
{
SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin();
SomeClass::SomeContainer::iterator IterEnd = m_SomeMemberContainerVar.end();
for (; Iter != IterEnd; ++Iter)
{
}
}
This is supposed to give a speed and efficiency gain, especially if you are programming consoles, because the .end() function is not called on each iteration of the loop. I just take the performance improvement for granted, it sounds reasonable but i don't know how much and it certainly depends on the type of container and actual STL implementation in use. But having used this style for a couple months now i actually prefer it over the first anyway.
The reason being readability: the for line is neat and tidy. With qualifiers and member variables in real production code it is quite easy to have really long for lines if you use the style in the first example. That's why i intentionally made it to have a horizontal scrollbar in this example, just so you see what i'm talking about. ;)
On the other hand, you suddenly introduce the Iter variables to the outer scope of the for loop. But then, at least in the environment i work in, the Iter would have been accessible in the outer scope even in the first example.
What is your take on this? Are there any pro's to the first style other than possibly limiting the scope of Iter?
If you wrap your code into lines properly, the inline form would be equally readable. Besides, you should always do the iterEnd = container.end() as an optimization:
for (SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin(),
IterEnd = m_SomeMemberContainerVar.end();
Iter != IterEnd;
++Iter)
{
}
Update: fixed the code per paercebal's advice.
Another alternative is to use a foreach macro, for example boost foreach:
BOOST_FOREACH( ContainedType item, m_SomeMemberContainerVar )
{
mangle( item );
}
I know macros are discouraged in modern c++, but until the auto keyword is widely available this is the best way I've found to get something that is concise and readable, and still completely typesafe and fast. You can implement your macro using whichever initialization style gets you better performance.
There's also a note on the linked page about redefining BOOST_FOREACH as foreach to avoid the annoying all caps.
The first form (inside the for loop) is better if the iterator is not needed after the for loop. It limits its scope to the for loop.
I seriously doubt that there is any efficiency gain either way. It can also be made more readable with a typedef.
typedef SomeClass::SomeContainer::iterator MyIter;
for (MyIter Iter = m_SomeMemberContainerVar.begin(); Iter != m_SomeMemberContainerVar.end(); ++Iter)
{
}
I would recommend shorter names ;-)
Having looked at this in g++ at -O2 optimisation (just to be specific)
There is no difference in the generated code for std::vector, std::list and std::map (and friends). There is a tiny overhead with std::deque.
So in general, from a performance viewpoint it makes little difference.
No, it's a bad idea to get a hold on iter.end() before the loop starts. If your loop changes the container then the end iterator may be invalidated. Also, the end() method is guaranteed to be O(1).
Premature optimization is the root of all evil.
Also, the compiler may be smarter than you think.
I don't have a particularly strong opinion one way or the other, though iterator lifetime would lean me toward the for-scoped version.
However, readability may be an issue; that can be helped by using a typedef so the iterator type is a bit more manageable:
typedef SomeClass::SomeContainer::iterator sc_iter_t;
for (sc_iter_t Iter = m_SomeMemberContainerVar.begin(); Iter != m_SomeMemberContainerVar.end(); ++Iter)
{
}
Not a huge improvement, but a bit.
I don't have any console experience, but in most modern C++ compiliers either option ends up being equivilent except for the question of scope. The visual studio compilier will virtually always even in debug code put the condition comparison in an implicit temporary variable (usually a register). So while logically it looks like the end() call is being made through each iteration, the optimized compiled code actually only makes the call once and the comparison is the only thing that is done each subsiquent time through the loop.
This may not be the case on consoles, but you could unassemble the loop to check to see if the optimization is taking place. If it is, then you can you whatever style you prefer or is standard in your organization.
It may make for disjointed code, but I also like to pull it out to a separate function, and pass both iterators to it.
doStuff(coll.begin(), coll.end())
and have..
template<typename InIt>
void doStuff(InIt first, InIt last)
{
for (InIt curr = first; curr!= last; ++curr)
{
// Do stuff
}
}
Things to like:
Never have to mention the ugly iterator type (or think about whether it's const or not-const)
If there is gain from not calling end() on each iteration, I'm getting it
Things to not like:
Breaks up the code
Overhead of additional function call.
But one day, we'll have lambdas!
I don't think it's bad style at all. Just use typedefs to avoid the STL verbosity and long lines.
typedef set<Apple> AppleSet;
typedef AppleSet::iterator AppleIter;
AppleSet apples;
for (AppleIter it = apples.begin (); it != apples.end (); ++it)
{
...
}
Spartan Programming is one way to mitigate your style concerns.
You can throw braces around the initialization and loop if you are concerned about scope. Often what I'll do is declare iterators at the start of the function and reuse them throughout the program.
I agree with Ferruccio. The first style might be preferred by some in order to pull the end() call out of the loop.
I might also add that C++0x will actually make both versions much cleaner:
for (auto iter = container.begin(); iter != container.end(); ++iter)
{
...
}
auto iter = container.begin();
auto endIter = container.end();
for (; iter != endIter; ++iter)
{
...
}
I would usually write:
SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin(),
IterEnd = m_SomeMemberContainerVar.end();
for(...)
I find the second option more readable, as you don't end up with one giant line. However, Ferruccio brings up a good point about the scope.