What's the point of iterators? [duplicate] - c++

This question already has answers here:
Why use iterators instead of array indices?
(27 answers)
Closed 10 years ago.
Why should I use iterators?
For example if I have code like this:
for (int i = 0; i < vec.size(); i++)
cout << vec[i];
what would be the advantage of writing
for (vector<int>::iterator it != vec.begin(); it != n.end(); ++it)
cout << *it;
Also, why is writing i < vec.size() and i++ more common in the first example and it != begin() and ++it more common in the second example? What is the difference how you increment it and why not always use an equal sign?
I understand iterators can be useful in C++11 range-based for loops and some STD algorithms, but why should I do it in normal code, since it is more verbose?

Well not all containers have random access so you can do lookup on an index, so to normalize the interface iterators are fairly useful. Consider std::list. It doesn't support random access via a [] operator.
Taking this into account, to work across many heterogeneous types of containers, many STL functions like std::copy take iterators.

The point is that iterators allow you to iterate over anything that supports iterators in a generic fashion.
As for it being more verbose, the extra verbosity isn't horrible (and your example could be slightly improved using auto or using the C++11 range-based for loop) but that's really a stylistic issue.

Lets say we have this code:
typedef std::vector<std::string> strings;
strings strs;
for( strings::const_iterator it = strs.begin(); it != strs.end(); ++it ) {
}
And later for watever reason we decide to switch to std::list. So we just replace typedef and code:
typedef std::list<std::string> strings;
strings strs;
for( strings::const_iterator it = strs.begin(); it != strs.end(); ++it ) {
}
Will work as before. But code with index variable will fail. Imagine what if you need to write a template code.

The tl;dr is that iterators work better in a general case for different kinds of objects (when for example the size() method may be slow).
If you want to read more about it:
Why use iterators instead of array indices?
Iterators.. why use them?

Related

C++: list iterators vs. vector iterators

I thought the idea of the iterator object was that you can apply it similarly to the C++ container classes. When I try to iterate through a list object, however, I tried using
for(list<int>::iterator it = obj.begin(); it < obj.end(); it++){
// some code
}
And I got an error. Why doesn't this work? Why would it work for vector::iterator? Is it just because of the implementation of list being bi-directional linked lists? I thought the iterator object abstracts that notion of moving through containers, thereby allowing it to operationally be the same, whether for vectors or lists.
I'd really appreciate a clarification.
This does not work because, unlike std::vector iterators, std::list iterators are not random-access - they are sequential. You need to use != on them:
for(list<int>::iterator it = obj.begin(); it != obj.end(); it++)
In general, it's a good idea to use "not equals" on all iterators when you are looking to cover the entire range, even when these iterators allow comparisons for < and >. There is also an argument in favor of using != in your regular for loops, too, because it gives you the strongest postcondition.
You have to compare with != as list iterators are scattered throughout all memory in random order.
Use: for(list<int>::iterator it = obj.begin(); it != obj.end(); it++)
That's because list does not support random access iterators, but only forward iterators. Therefore, operator < is not defined for iterators of a list. You have to use operator != for inequality comparisons.
Operator arithmetic, including ordering-comparison operators (like <), is only defined for random access iterators. If you change the code to use !=, it will work (assuming obj is a list<int>):
for(list<int>::iterator it = obj.begin(); it != obj.end(); it++){
// some code
}

loop through several vectors

I had trouble searching for potential duplicates because I'm not sure what the correct terminology is.
If I have many vectors which are already created, how can I loop through them? To make things simple, suppose I have three vectors of strings named "vec_one", "vec_two", "vec_three".
I want to do something like:
for i in ("vec_one", "vec_two", "vec_three") {
for (vector<string>::const_iterator iter = i.begin(); iter != i.end(); ++iter) {
//do something with the elements ***and I need to access "i"***, that is, the vector name.
}
}
This would be the same as writing three different for loops, but would be more readable and in fact I have more than three in my non-simple application.
Note that because I need to access the vector name (see the comment), I can't just merge them all together and then run one loop.
You can do it with an array:
const vector<string>* varr[] = { &vec_one, &vec_two, &vec_three, &etc };
for (auto vec = begin(varr); vec < end(varr); ++vec)
for (vector<string>::const_iterator iter = begin(**vec); iter != end(**vec); ++iter)
//do something with the elements
You could put the the vectors in a vector<std::pair<std::string, std::vector<...>*>:
std::vector<std::pair<std::string, std::vector<std::string>*> > vectors;
vectors.emplace_back(std::string("vec_one"), &vec_one); //or push_back(std::make_pair(...)) in C++03
vectors.emplace_back(std::string("vec_two"), &vec_two);
vectors.emplace_back(std::string("vec_three"), &vec_three);
for(auto iter = vectors.begin(); iter != vectors.end(); ++iter)//used c++11 auto here for brevity, but that isn't necessary if C++11 is not availible
for(auto vecIter = iter->second->begin(); vecIter != iter->second->end(); ++vecIter)
//get name with iter->first, body here
That way you can get the name easily from the outer iterator.
If you use C++11 you can use std::array instead:
std::array<std::pair<std::string, std::vector<std::string>*>, 3> vectors =
{
std::make_pair(std::string("vec_one"), &vec_one),
std::make_pair(std::string("vec_two"), &vec_two),
std::make_pair(std::string("vec_three"), &vec_three)
};
In C++03 you could use buildin arrays instead, but unless the extra overhead for the vector is a problem for you (unlikely) I don't see a compelling reason to do so. boost::array is also a noteworthy alternative if you can't use C++11
If you do need the absolute optimal performance it might be worthwile to directly use const char* instead of std::string for the names.
Probably the easiest way would be to have your vectors in an array (or a vector-of-vectors if there is a variable number of them).
I guess you'd also want an array of "vector names" to satisfy your second condition.

what is the better way to write iterators for a loop in C++

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)

c++ best way to use for loop

I have this question that runs in my mind...
I have a std::vector to iterate:
which is the best way (the faster) to iterate?
here is the code using an iterator:
// using the iterator
for( std::vector <myClass*>::iterator it = myObject.begin( ); it != myObject.end( ); it++ )
{
(*it)->someFunction( );
}
and here is 'normal' mode...
// normal loop
for( int i = 0; i < myObject.Size( ); i++ )
{
myObject[i]->someFunction( );
}
thanks for your suggestions!
None of the two will be any faster really, because on most implementations a vector<T>::iterator is just a typedef for T* and size is cached.
But doing ++it instead of it++ is a good habit. The latter involves creating a temporary.
for(std::vector <myClass*>::iterator it = myObject.begin( );
it != myObject.end( );
++it)
^^^^
On other containers such as map, list etc. with nontrivial iterators the difference between postincrement and preincrement might become noticable.
If you really care, you can find out: Just make a single source file with one function with that loop and look at the optimized assembly:
g++ -O2 -S -o ver1.s ver1.cpp
g++ -O2 -S -o ver2.s ver2.cpp
You can directly see the differences! I bet there are none.
That said, you should use the iterator pattern because it's idomatic, generic C++ and it gets you in the right mood -- plus, it works in far more general cases than just vectors! Write it like this:
typedef std::vector<MyClass*> myVec;
for (myVec::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
const MyClass & x = **it;
/* ... */
}
In case you're curious, a vector iterator is most likely just going to be a native, raw pointer, so there's really nothing to fear in terms of efficiency, and a lot to be enjoyed from the self-explanatory, algorithmic style!
PS If you have C++0x, say it like this:
for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
// or
for (const MyClass * & i : v)
The first code will decompose into incrementing a pointer. The second one will increment an index, and index into the array. The first one can use slightly smaller instructions (and thus potentially be faster) assuming the compiler doesn't optimize the second into the first already. But it will be a trivial difference.
Iterators should be preferred, however, not because of speed but because you can then easily move the code to iterate any standard C++ container, not just vector.
However, you've got a few things to improve.
Don't use it++, but ++it. This can be very important in C++ because iterators can end up doing a little more work in post-increment which won't be optimized out as if the type were an int.
Don't constantly call end() or size(). For some iterator types and collections this might not be optimized out and can be very sub-optimal.
Use vector::size_type when you need an index into a vector. int is not guaranteed to be big enough, while size_type was made specifically for that.
So, the better ways to write these are:
// using the iterator
for(std::vector <myClass*>::iterator it = myObject.begin( ), end = myObject.end(); it != end; ++it)
{
(*it)->someFunction( );
}
// normal loop
for(std::vector <myClass*>::size_type i = 0, size = myObject.size(); i < size; ++i)
{
myObject[i]->someFunction( );
}
Here's what I use:
int s = vec.size();
for(int i=0;i<s;i++)
{
T &o = vec[i];
...
}
This loop has the following advantages over other approaches:
it always looks the same (unlike the hacks that change from i++ to ++i)
it's relatively short to write (compared to the iterator version)
the int indexes are useful in your public interface (unlike iterators)
it still always looks the same (unlike stdlib algorithms, where you need documentation to remember the parameters)
it's very old and thus widely used. (originally comes from book "The C programming language" aka K&R)
It doesn't give warnings on most compilers (unlike the loop that was used in the question)
It does have some disadvantages too:
some newer programmers doesn't like it because they think C ways are too old
in a const function, you might need to change it slightly to const T &o = vec[i]; or change the data member mutable
type T changes depending on the use
You can do this:
#include <iostream>
using namespace std;
int main() {
for (int i = 3; i > 0; i--) {
cout << i << "\n";
}
return 0;
}
source https://mockstacks.com/Cpp_For_Loop

Use a regular iterator to iterate backwards, or struggle with reverse_iterator?

I recently learned about the right way to work with reverse iterators in C++ (specifically when you need to erase one). (See this question and this one.)
This is how you're supposed to do it:
typedef std::vector<int> IV;
for (IV::reverse_iterator rit = iv.rbegin(), rend = iv.rend();
rit != rend; ++rit)
{
// Use 'rit' if a reverse_iterator is good enough, e.g.,
*rit += 10;
// Use (rit + 1).base() if you need a regular iterator e.g.,
iv.erase((rit + 1).base());
}
But I think thought this is much better (Don't do this, not standards compliant, as MooingDuck points out):
for (IV::iterator it = iv.end(), begin = iv.begin();
it-- != begin; )
{
// Use 'it' for anything you want
*it += 10;
iv.erase(it);
}
Cons:
You tell me. What's wrong with it?
It's not standards compliant, as MooingDuck points out. That pretty much overrules any of the possible advantages below.
Pros:
Uses a familiar idiom for reverse for-loops
Don't have to remember (or explain) the +1
Less typing
Works for std::list too: it = il.erase(it);
If you erase an element, you don't have to adjust the iterator
If you erase, you don't have to recompute the begin iterator
The reason for reverse iterators is that the standard algorithms do not know how to iterate over a collection backwards. For example:
#include <string>
#include <algorithm>
std::wstring foo(L"This is a test, with two letter a's involved.");
std::find(foo.begin(), foo.end(), L'a'); // Returns an iterator pointing
// to the first a character.
std::find(foo.rbegin(), foo.rend(), L'a').base()-1; //Returns an iterator
// pointing to the last A.
std::find(foo.end(), foo.begin(), L'a'); //WRONG!! (Buffer overrun)
Use whichever iterator results in clearer code.
For what it's worth, Scott Meyers' Effective STL recommends that you just stick with a regular ol' iterator (Item 26).