WEBVTT

00:02.780 --> 00:06.560
Hello again! In this video, we're going to look at loops and iterators.

00:07.160 --> 00:11.570
There's actually several different types of its iterators, and we're going to go through those, and look

00:11.570 --> 00:14.360
at how to use them with loops over containers.

00:17.740 --> 00:20.170
The first one is the const iterator.

00:20.650 --> 00:26.050
So this is used to access the elements in a container, but without being able to modify them.

00:27.590 --> 00:33.110
The name is const underscore iterator. Again, it's a member of the container class.

00:33.380 --> 00:39.350
So if we have a const iterator to a string, it'll be string double colon const underscore iterator.

00:41.560 --> 00:48.310
And we can use this just like a regular iterator, so we can call, begin and compare the results to

00:48.310 --> 00:52.390
end and increment to step through the elements in a container.

00:56.210 --> 00:57.540
There's two uses for this.

00:57.560 --> 01:03.470
One is if you simply want to iterate and make sure that you don't accidentally change anything. The other

01:03.470 --> 01:08.000
one is, if you have a const container, then you need to use a const iterator with it.

01:08.930 --> 01:13.880
And the most common circumstance is if you're in a function body and you've been passed a const

01:13.910 --> 01:19.940
container. You'll remember that's the best way generally to pass large objects is by reference to const.

01:20.360 --> 01:25.430
So in that case, you'll have a const container and you need to use a const iterator with that.

01:29.110 --> 01:32.710
A slightly more complex one is the reverse iterator.

01:32.950 --> 01:39.570
So this will actually iterate backwards through a container, so we have string double colon reverse

01:39.580 --> 01:43.330
iterator. And this literally does work backwards.

01:43.600 --> 01:49.720
So when you call begin, or rather rbegin, this will return a reverse iterator.

01:50.110 --> 01:52.720
And this will be pointing to the last element in the string.

01:53.590 --> 01:58.360
So if we have the string "hello", rbegin will return an iterator which points to the letter 'o'.

01:59.680 --> 02:05.320
And then if we increment that, it'll move backwards through the string, so it'll then be pointing

02:05.320 --> 02:07.080
to the last letter 'l'.

02:07.780 --> 02:12.400
Then if we keep on incrementing, it goes [to] the next 'l', then the 'e' and then the 'H'.

02:12.850 --> 02:19.480
And if we increment it again, we go past the first element in the string and then we get an iterator

02:19.480 --> 02:22.120
which is equal to the result of calling rend.

02:24.820 --> 02:30.250
So the actual form of the loop looks exactly the same, but the results are backwards.

02:30.730 --> 02:31.180
So.

02:32.320 --> 02:37.240
When we begin, we start at the back of the string, then we increment to go backwards.

02:38.050 --> 02:41.800
And then when we go past the front of the string, we stop the loop.

02:45.020 --> 02:51.350
So here we are, we've got our string hello. Then we're doing this with a normal iterator, just to remind

02:51.350 --> 02:52.310
ourselves what that does.

02:52.970 --> 02:55.100
And then we're going to do this with a reverse iterator.

02:55.730 --> 02:57.230
So that's the code we had on the slide.

02:58.340 --> 02:59.660
So what happens?

03:04.150 --> 03:10.510
So there we are, the normal iterator prints out the characters in the normal order, going left to right.

03:11.050 --> 03:16.360
And the reverse iterator prints them out in reverse order, starting with the last element and ending

03:16.360 --> 03:16.960
with the first.

03:18.380 --> 03:18.740
OK.

03:29.460 --> 03:37.560
C++ now provides member functions, so we can use const iterators with auto. So we can call cbegin and cend

03:37.560 --> 03:39.870
those will return const iterators.

03:40.650 --> 03:45.960
So if we want to loop through our string without altering it, then we call cbegin instead of begin

03:45.960 --> 03:51.480
and cend instead of end. And the compiler will deduce the type automatically.

03:51.870 --> 03:57.720
It'll see that this returns a const iterator, so it needs to be a const iterator to string.

03:59.160 --> 04:04.170
And then there's also a couple of other member functions. If you want a const reverse iterator.

04:04.590 --> 04:10.620
So if you want to go backwards without changing anything you call crbegin and crend,

04:12.240 --> 04:15.440
and the compiler will deduce this as a const reverse iterator.

04:15.960 --> 04:18.090
So that's also a new type in C++

04:18.090 --> 04:18.420
11.

04:21.950 --> 04:26.120
So let's just remind ourselves so we have the standard iterator with begin and end.

04:26.810 --> 04:32.870
We have the const iterator with cbegin and cend. We have the reverse iterator with rbegin and

04:33.200 --> 04:33.590
rend.

04:34.190 --> 04:39.050
And then we have the const reverse iterator with crbegin and crend.

04:44.050 --> 04:49.420
So there we are, the iterator and the const iterator, all provide the - well, I'm sure you can

04:49.540 --> 04:50.500
work out what's going on!

04:54.010 --> 04:58.330
So there we are, we have four different types of iterator for iterating through a container.

05:01.920 --> 05:08.730
Also in C++ 11, there are non-member begin and end functions. So you can call these without having

05:08.730 --> 05:11.130
to write a member function call.

05:11.550 --> 05:15.630
And I would say that these are more readable than the alternatives with a member function.

05:15.960 --> 05:22.620
So instead of saying str dot begin, you'd say begin with str as the argument. And then end with the

05:22.620 --> 05:27.360
string as the argument. And apart from that, it works exactly the same.

05:27.960 --> 05:31.020
The big advantage this is they also work with built-in arrays.

05:31.410 --> 05:34.740
Of course, arrays are built-in types, so they don't have member functions.

05:35.220 --> 05:40.950
So you can iterate over arrays, just like you can do with strings or vectors or other library containers.

05:42.930 --> 05:47.120
So you call begin with the array as the argument and end with the array as the argument and then you can

05:47.190 --> 05:50.520
iterate through them. And then C++ 14.

05:50.820 --> 05:56.160
They also added the missing versions, so that's pretty much C++ 14, really, which is just filling in all the

05:56.160 --> 05:59.250
gaps from C++ 11 and adding a few "nice to haves."

06:01.170 --> 06:09.470
So we have see cbegin for const iterators, rbegin for reverse iterators and crbegin for const reverse

06:09.570 --> 06:09.960
iterators.

06:13.100 --> 06:15.740
And we can try that out. So we've got an array here.

06:17.450 --> 06:23.210
Then we have all these different forms of iterators, using the global calls. Because we can't use

06:23.210 --> 06:26.030
the member functions because arrays don't have member functions.

06:30.450 --> 06:32.490
And there we are, that's what we would expect.

06:38.780 --> 06:44.360
And finally, we're going to look at range-for loops. so this is a special, concise syntax for

06:44.360 --> 06:45.830
iterating over containers.

06:46.820 --> 06:52.260
So if you are just doing the standard loop where you start at the beginning and look at each element

06:52.260 --> 06:56.660
at once and stop when you get to the end, this is a much shorter way of writing it.

06:58.070 --> 07:04.210
So we're using auto, then we have the container and then before the container, we have this colon

07:04.940 --> 07:10.970
and then we have some variable. And this variable is going to represents each element on the container

07:11.300 --> 07:12.140
on the iteration.

07:12.740 --> 07:15.860
So the first time through that's going to be the first element of the second time to it's going to be

07:15.860 --> 07:17.090
the second element and so on.

07:17.900 --> 07:22.220
And when the compiler does that, it's actually going to generate the code for the loop.

07:23.060 --> 07:28.760
So to get this element, it will dereference the iterator and then copy the

07:29.640 --> 07:35.790
dereferenced iterator into this variable. So this is actually going to be a copy of the element.

07:36.300 --> 07:41.580
So if we try to make any changes to the element in here, it's not going to affect the container.

07:44.450 --> 07:46.640
So these two forms are exactly equivalent.

07:46.910 --> 07:49.190
This is just a shorthand for that.

07:52.710 --> 07:56.790
So what happens if we do want to be able to modify the elements in the loop?

07:57.660 --> 08:00.900
We can do that by slipping in a reference after the auto.

08:02.040 --> 08:06.990
So you remember that if we use auto, it'll always give the actual type and ignore any const or reference.

08:07.440 --> 08:12.390
If we add a reference to the auto, then it's going to be a reference to the element type.

08:12.810 --> 08:18.840
So if we have a vector of int, then el is going to be a reference to int.

08:19.320 --> 08:23.820
And then the actual element in here is going to be a reference to the element in the vector.

08:25.700 --> 08:31.160
So when we write this code, the compiler will generate this. So this looks a bit strange, but

08:31.160 --> 08:31.820
it does work.

08:32.150 --> 08:39.080
So it dereferences the iterator to get the element value and then it initializes a reference to

08:39.080 --> 08:39.830
that element.

08:40.670 --> 08:42.710
So this is going to be a reference to the element.

08:43.010 --> 08:47.690
So when we modify this reference, it will also modify the element.

08:50.120 --> 08:50.540
OK.

08:52.210 --> 08:53.410
So let's try that out.

08:55.000 --> 09:01.260
We've got a vector, and then we're going to use a range for loop to iterate over that.

09:01.720 --> 09:04.150
So this is going to print every element in the vector.

09:04.600 --> 09:11.410
This is just equivalent to a loop which has "for auto iterator equals vec dot begin, not equals end,

09:11.680 --> 09:12.790
"plus plus iterator."

09:14.710 --> 09:20.410
Then we're going to use the reference form, so this element is going to be a reference to the element

09:20.410 --> 09:20.980
in the vector.

09:22.120 --> 09:27.460
So this is going to add two to each element and then we're going to do the first loop again to see

09:27.460 --> 09:30.070
what we've actually got in the vector after doing that operation.

09:30.820 --> 09:33.570
So we had one two three four before.

09:33.580 --> 09:36.760
So we should, we hope, get three four five six.

09:39.080 --> 09:40.550
Let's see what happens.

09:42.020 --> 09:45.110
There we are, so the first loop puts out the elements in the vector.

09:46.130 --> 09:48.110
So these are just copies of the vector elements.

09:48.560 --> 09:51.770
Then in the second loop, we have references to the element.

09:51.800 --> 09:53.390
So we're adding two to each element.

09:54.410 --> 09:59.480
And then in the final loop, we're printing out the elements again and we do get three four five

09:59.480 --> 09:59.840
six.

10:03.200 --> 10:05.210
So these range-for loops are very useful.

10:06.170 --> 10:10.100
You know, a lot of times you are just watching a loop where you go over all the elements.

10:10.370 --> 10:14.300
You may be doing something a bit more complex than printing them out, but it is something that you do a lot

10:14.320 --> 10:19.490
of in C++. And this will make your code a lot shorter and easier to read.

10:22.490 --> 10:25.760
So I'd recommend that you use range-for loops wh... (Argh!)

10:29.300 --> 10:31.460
So when should you use range-for loops?

10:31.850 --> 10:35.210
I recommend that you use them all the time. Whenever it's possible.

10:36.740 --> 10:41.270
Obviously, there are some situations where you can't do that. If you only want to look at some of the

10:41.270 --> 10:47.030
elements in the container, if you want to go in a different order or skip out elements.

10:47.480 --> 10:51.710
And also, if you add or remove elements from the container, then that won't work properly.

10:52.130 --> 10:57.350
So in that case, you need to use the traditional loop and you may need to tweak it a bit to make it

10:57.350 --> 11:02.300
do what you want. But otherwise, if you are just going through all the elements in order and you're

11:02.300 --> 11:07.190
not actually modifying the container, then range for loops are really useful and they are one of the

11:07.190 --> 11:08.620
best features of C++11.

11:09.170 --> 11:09.380
I would say.

11:11.050 --> 11:12.740
Okay, so that's it for this video.

11:13.190 --> 11:14.050
I'll see you next time.

11:14.060 --> 11:16.100
But meanwhile, keep coding!
