WEBVTT

00:01.260 --> 00:05.100
Hello again! In this video, we're going to have an introduction to iterators.

00:07.010 --> 00:11.510
If you've done a traditional C++ course, you've probably seen code like this. So you have an array

00:11.510 --> 00:15.080
of characters, or ints, or objects of some kind.

00:16.710 --> 00:20.850
If you use the name of the array on its own, that's a pointer to the first element.

00:21.330 --> 00:23.280
So we have p pointing to the first element.

00:24.210 --> 00:30.420
And then if you add the number of elements, you get a pointer which points just after the last element.

00:31.890 --> 00:33.930
So that does point to memory, but not to memory

00:33.930 --> 00:35.040
that is part of the array.

00:35.970 --> 00:40.320
Then you have this pointer, you can [dereference] it to get the first element.

00:40.830 --> 00:45.060
Then you increment it to move on to the second element. And you keep on doing that.

00:45.540 --> 00:51.900
And then when this pointer is equal to the last plus one element, you terminate the loop, so you

00:51.900 --> 00:53.760
stop dereferencing and incrementing it.

01:00.440 --> 01:05.100
So the final value of the pointer is not the address of any element in the actual array.

01:05.660 --> 01:10.370
If you use that pointer, then you get undefined behaviour, and I'm sure you've all seen that!

01:11.720 --> 01:15.290
So this pointer represents an imaginary element after the last element.

01:20.020 --> 01:24.890
When we're using standard string, we could use the same approach, because that's implemented as an

01:24.890 --> 01:29.830
array. We can get the address of the first elements and use a pointer to that and increment it.

01:30.370 --> 01:32.050
But that's not really the right way to do things.

01:33.010 --> 01:37.720
It'll work for string and vector, which are implemented as arrays, but there are other containers in

01:37.720 --> 01:40.510
the standard library which are not, and that approach won't work.

01:41.110 --> 01:42.610
So let's learn the proper way to do it.

01:42.940 --> 01:43.960
For library containers.

01:44.560 --> 01:47.260
We use something called an iterator, and it works the same way.

01:47.680 --> 01:49.900
So we have some standard string.

01:50.770 --> 01:54.910
We get an iterator instead of a pointer, which represents the first element.

01:55.630 --> 01:59.350
This is a member of the string object.

01:59.380 --> 02:00.520
It's a class itself.

02:01.240 --> 02:05.230
It may be implemented around a pointer, but it doesn't really matter. We don't need to know how it

02:05.230 --> 02:05.680
works.

02:07.730 --> 02:13.160
And then we compare the current position of the iterator to the last plus one element.

02:14.030 --> 02:18.710
And then if it's all okay, we can dereference the iterator and that'll give us the data in the

02:18.710 --> 02:22.250
current element. And then we increment it to move on to the next element.

02:22.820 --> 02:26.710
So it has exactly the same form as the loop that we had before.

02:26.720 --> 02:28.850
It's just we're using iterators instead of pointers.

02:32.710 --> 02:37.960
So the question is, what do we do to get these iterators? And the string provides two member functions

02:37.960 --> 02:43.930
which will do that. The begin member function will return an iterator to the first element and the end

02:43.930 --> 02:48.340
member function will return an iterator to the last plus one element.

02:49.480 --> 02:51.430
So that's the element off the end of the string.

02:53.030 --> 02:58.040
And, as with pointers, that's not a valid iterator. If you dereference it, you get undefined

02:58.040 --> 02:58.550
behaviour.

02:59.360 --> 03:03.680
And also these iterators are specific to the object that you call the member function on.

03:04.220 --> 03:06.860
If you try to mix them with iterators to other objects,

03:07.250 --> 03:08.690
again, you get undefined behaviour.

03:09.380 --> 03:14.210
So if you have begin() from one string object and and end() from a different string object, your program

03:14.540 --> 03:15.020
is probably going to crash.

03:20.470 --> 03:26.110
So this is what it might look like in memory. So we have the string object header with the element

03:26.110 --> 03:32.530
count and the pointer to the data. Then we have this memory block, which contains the data. When we

03:32.530 --> 03:33.140
call begin,

03:33.160 --> 03:35.590
we get an iterator to this first element.

03:39.040 --> 03:42.790
Then we dereference the iterator, to get the data in this element.

03:43.570 --> 03:47.260
And when we increment the iterator, it moves on to the next element.

03:49.520 --> 03:54.590
And then we have this non-existent element, the last plus one element.

03:55.370 --> 03:59.450
And this corresponds to the return value from the end member function.

04:04.520 --> 04:05.840
So now we can finish off the loop.

04:06.170 --> 04:12.670
We say that the iterator equals the result of calling begin() on this string, and then we want to compare

04:12.680 --> 04:14.540
it to the result of calling end().

04:17.200 --> 04:22.570
So begin will be the start of the string and the iterator will be incremented as we go through it.

04:23.170 --> 04:28.210
If the iterator is equal to the return value from end(), we know that we've seen all the data and we need

04:28.210 --> 04:29.980
to stop and terminate the loop.

04:32.060 --> 04:37.730
And one useful feature of this is that, if there's no data in the container, if it's empty, then begin()

04:37.730 --> 04:39.650
and end() will return the same value.

04:40.070 --> 04:44.480
So this will fail and the loop body does not get executed at all.

04:47.350 --> 04:49.180
So here is our code for this.

04:50.290 --> 04:51.760
So we have our string.

04:52.510 --> 04:55.360
We call begin to get the iterator to the first element.

04:55.720 --> 04:58.330
And then we compare it to the last plus one element.

05:02.610 --> 05:05.540
So we get the elements in the string, H e l l o.

05:10.150 --> 05:12.760
And just to show that nothing happens if it's empty.

05:16.770 --> 05:17.400
So there we are.

05:18.420 --> 05:19.530
We don't get any output.

05:19.800 --> 05:21.450
The loop doesn't get executed.

05:26.640 --> 05:33.930
And in fact, we can simplify this by writing it as a for loop so we can do.. for iterator equals

05:33.930 --> 05:34.290
begin()

05:38.500 --> 05:40.780
While the iterator is not equal to the end of the string.

05:47.810 --> 05:49.520
Then we increment it.

05:55.550 --> 05:58.430
Nope, made a mistake somewhere. Ah, extra semi-colon.

06:03.070 --> 06:04.470
(The danger of copying and pasting!)

06:04.800 --> 06:06.060
Okay, so you can see that works.

06:06.360 --> 06:08.310
That's exactly the same, equivalent loop.

06:11.300 --> 06:13.550
And we can also do this with a vector as well.

06:13.700 --> 06:18.380
In fact, we can do it with any container, but we didn't know any others, apart from string and vector at

06:18.380 --> 06:18.890
the moment.

06:20.060 --> 06:22.460
So we define our vector.

06:24.560 --> 06:26.660
Then we get an iterator to the first element.

06:27.830 --> 06:32.000
So the int parameter is actually part of the type for the object, so we need to include that.

06:33.410 --> 06:37.840
Then we can get our iterator to the first element. Then we compare it against the last

06:37.860 --> 06:38.300
plus one

06:38.300 --> 06:40.220
iterator and...

06:41.910 --> 06:43.620
There we go, three one four one five nine.

06:44.730 --> 06:46.650
Okay, so that's it for this video.

06:47.010 --> 06:47.820
I'll see you next time.

06:47.820 --> 06:49.860
But meanwhile, keep coding!
