An iterator is an object that moves through a container of other objects and selects them one at a time without providing direct access to the implementation of that container. Iterators provide a standard way to access elements, whether or not the container provides a way to access the elements directly.
Iterators are sometimes referred to as smart pointers. Why? A lot of the operations mimic those for pointers, and this is a deliberate abstraction.
Actually pointers tied to arrays are iterators it’s just they aren’t typically introduced with the iterator functionality that general pointers don’t have.
Smart because they are designed to be safe and at the least help you detect when you are past the end of your container, like the end of an array.
This is somewhat confusing though, since smart pointers are actually something else, which is related but not the same.
We should aim for every iterator in our programs to have the same interface so any code using the iterator doesn’t care what it’s pointing to.
This supports generic programming.
A common solution is to added nested iterator class to each container class written.
You don’t need to write iterators for your assignment containers.
With pointers we use the address-of operator to point at something in particular.
For types supporting iterators we instead have members returning particular iterators.
For an object v of a type with iterators:
auto b = v.begin();
auto e = v.end();
... begin is an iterator denoting the first element, and end the off-the-end iterator denoting the position one past the last element.
Here goes an example that illustrates the use of an iterator, in this case for a string.
The string class is not actually a container class but it has a lot of functionality in common with containers and we have at least seen it before.
string s("this is a string");
if (s.begin() != s.end()){
auto it = s.begin();
*it = toupper(*it);
}
To step through elements in our string we can do the following:
for (auto it=s.begin(); it != s.end(); ++it)
cout << *it << " ";
cout << endll;
The " " highlights the element by element. When we talked about defensive programming we mentioned that < is safer as a test than !=. Well < is often undefined, while != will be defined for iterators so the != form is going to be widely used.
The type of iterator pointing to a const object is different to that not.
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
string s1("this is a string");
const string s2("this is a string too");
auto it1 = s1.begin();
auto it2 = s2.begin();
cout << typeid(it1).name() << endl;
cout << typeid(it2).name() << endl;
}
$ g++ constIT.cpp
$ ./a.out
05:22:25 $ ./a.out
N9__gnu_cxx17__normal_iteratorIPcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE
N9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE