Hello again! In this video, we're going to have an introduction to iterators.
If you've done a traditional C++ course, you've probably seen code like this. So you have an array
of characters, or ints, or objects of some kind.
If you use the name of the array on its own, that's a pointer to the first element.
So we have p pointing to the first element.
And then if you add the number of elements, you get a pointer which points just after the last element.
So that does point to memory, but not to memory
that is part of the array.
Then you have this pointer, you can [dereference] it to get the first element.
Then you increment it to move on to the second element. And you keep on doing that.
And then when this pointer is equal to the last plus one element, you terminate the loop, so you
stop dereferencing and incrementing it.
So the final value of the pointer is not the address of any element in the actual array.
If you use that pointer, then you get undefined behaviour, and I'm sure you've all seen that!
So this pointer represents an imaginary element after the last element.
When we're using standard string, we could use the same approach, because that's implemented as an
array. We can get the address of the first elements and use a pointer to that and increment it.
But that's not really the right way to do things.
It'll work for string and vector, which are implemented as arrays, but there are other containers in
the standard library which are not, and that approach won't work.
So let's learn the proper way to do it.
For library containers.
We use something called an iterator, and it works the same way.
So we have some standard string.
We get an iterator instead of a pointer, which represents the first element.
This is a member of the string object.
It's a class itself.
It may be implemented around a pointer, but it doesn't really matter. We don't need to know how it
works.
And then we compare the current position of the iterator to the last plus one element.
And then if it's all okay, we can dereference the iterator and that'll give us the data in the
current element. And then we increment it to move on to the next element.
So it has exactly the same form as the loop that we had before.
It's just we're using iterators instead of pointers.
So the question is, what do we do to get these iterators? And the string provides two member functions
which will do that. The begin member function will return an iterator to the first element and the end
member function will return an iterator to the last plus one element.
So that's the element off the end of the string.
And, as with pointers, that's not a valid iterator. If you dereference it, you get undefined
behaviour.
And also these iterators are specific to the object that you call the member function on.
If you try to mix them with iterators to other objects,
again, you get undefined behaviour.
So if you have begin() from one string object and and end() from a different string object, your program
is probably going to crash.
So this is what it might look like in memory. So we have the string object header with the element
count and the pointer to the data. Then we have this memory block, which contains the data. When we
call begin,
we get an iterator to this first element.
Then we dereference the iterator, to get the data in this element.
And when we increment the iterator, it moves on to the next element.
And then we have this non-existent element, the last plus one element.
And this corresponds to the return value from the end member function.
So now we can finish off the loop.
We say that the iterator equals the result of calling begin() on this string, and then we want to compare
it to the result of calling end().
So begin will be the start of the string and the iterator will be incremented as we go through it.
If the iterator is equal to the return value from end(), we know that we've seen all the data and we need
to stop and terminate the loop.
And one useful feature of this is that, if there's no data in the container, if it's empty, then begin()
and end() will return the same value.
So this will fail and the loop body does not get executed at all.
So here is our code for this.
So we have our string.
We call begin to get the iterator to the first element.
And then we compare it to the last plus one element.
So we get the elements in the string, H e l l o.
And just to show that nothing happens if it's empty.
So there we are.
We don't get any output.
The loop doesn't get executed.
And in fact, we can simplify this by writing it as a for loop so we can do.. for iterator equals
begin()
While the iterator is not equal to the end of the string.
Then we increment it.
Nope, made a mistake somewhere. Ah, extra semi-colon.
(The danger of copying and pasting!)
Okay, so you can see that works.
That's exactly the same, equivalent loop.
And we can also do this with a vector as well.
In fact, we can do it with any container, but we didn't know any others, apart from string and vector at
the moment.
So we define our vector.
Then we get an iterator to the first element.
So the int parameter is actually part of the type for the object, so we need to include that.
Then we can get our iterator to the first element. Then we compare it against the last
plus one
iterator and...
There we go, three one four one five nine.
Okay, so that's it for this video.
I'll see you next time.
But meanwhile, keep coding!