WEBVTT

00:00.840 --> 00:06.900
Hello again! In this video, we are going to look at stream iterators. The iterators we have used so far are

00:06.900 --> 00:12.480
designed for use with containers. They are so-called random access iterators, which means you can

00:12.480 --> 00:17.130
jump anywhere in a container. And it takes the same speed, whether you are going to the first element or the

00:17.130 --> 00:17.680
one millionth element.

00:20.190 --> 00:23.680
The standard library provides these iterators, which work on streams.

00:24.130 --> 00:25.950
They are defined in the iterator header.

00:26.640 --> 00:29.310
They can only work if all the data is of the same type.

00:30.330 --> 00:31.680
There is an input stream

00:31.680 --> 00:32.300
iterator,

00:32.400 --> 00:35.060
istream_iterator, and an output stream

00:35.070 --> 00:37.140
iterator, ostream_iterator.

00:37.920 --> 00:43.470
These are templated types, so we need to instantiate them. And we need to give a parameter, which is

00:43.470 --> 00:46.140
the type of the data that is going to be used with the stream.

00:47.730 --> 00:50.790
These stream iterators have a very limited interface.

00:51.270 --> 00:55.140
The only thing you can do with an output stream operator is to assign to it.

00:55.680 --> 01:02.040
And that will cause the argument of the operation to be pushed onto the stream. With an input stream

01:02.040 --> 01:03.080
[iterator], you can dereference it.

01:03.870 --> 01:07.350
And that will give you the object, which is at the current position in the stream.

01:08.280 --> 01:14.760
Or you can increment the iterator, and that will move the position market of the stream to the next object.

01:16.110 --> 01:18.840
So it will be ready to read the next object.

01:20.640 --> 01:26.070
The output stream operator does define these dereferencing and increment operators, but they do not

01:26.070 --> 01:26.820
actually do anything.

01:27.720 --> 01:32.970
They are just there, so you can write code that looks the same as any other code that uses iterators.

01:37.940 --> 01:43.550
To create an output stream iterator, we need to bind it to an output stream, and we do that by

01:43.550 --> 01:46.370
passing a stream object as the argument to the constructor.

01:47.030 --> 01:53.150
So here we have an output stream iterator, which will work with ints, and it is bound to cout, to

01:53.150 --> 01:54.260
the standard output.

01:54.680 --> 01:58.430
Every time that we assign to this iterator, data is pushed onto the stream.

02:01.540 --> 02:04.330
This is done using the left shift operator for the type.

02:04.570 --> 02:09.730
So if you have a data type that does not support the left shift operator, then this will not compile.

02:11.570 --> 02:15.050
So here we are assigning 7. Star oi equals 7.

02:15.740 --> 02:16.930
The star is optional here,

02:17.210 --> 02:23.110
but I have written it, so it looks the same as other iterator code. And that will actually cause the '7'

02:23.120 --> 02:24.770
to appear on the output.

02:29.040 --> 02:33.380
We can also provide a second argument, which is a delimiter, this is optional. Here,

02:33.390 --> 02:36.930
I have provided a backslash 'n', the newline character.

02:37.650 --> 02:39.330
This has to be a C string.

02:41.620 --> 02:46.750
And then when we assign to this iterator, the argument of the assignment, the variable i, will be sent

02:46.750 --> 02:49.090
to the stream, followed by a new line.

02:49.990 --> 02:57.610
So in this loop: each iteration, the value of i will be sent to the output stream, followed by a

02:57.610 --> 02:58.060
new line.

02:58.600 --> 03:02.740
So we should get the numbers from 0 to 9, each displayed on a separate line.

03:04.780 --> 03:06.220
So let's try this out.

03:07.600 --> 03:13.540
Here's the code with the iterator header. The output stream iterator. And then the loop, which

03:13.540 --> 03:15.490
assigns to the iterator.

03:15.850 --> 03:18.640
I have also included the increment as well, which is -

03:19.800 --> 03:22.800
Again, it does nothing, but it looks more consistent with iterator code.

03:25.320 --> 03:29.580
So there we are, we get the numbers from 0 to 9, each followed by a newline character.

03:32.160 --> 03:34.650
Creating an input stream operator is very similar.

03:35.070 --> 03:39.240
We give the data type as the parameter, and we bind it to an input stream.

03:39.720 --> 03:44.670
So this is an iterator, ii, which will read ints from the keyboard.

03:46.860 --> 03:51.390
And then, when we dereference this, it will read an integer from the keyboard.

03:56.120 --> 03:57.200
So let's try that.

03:58.830 --> 04:06.120
There is our stream iterator, than we dereference it. And then we store the value that it gets in a int and then

04:06.120 --> 04:07.470
we print out the value of that.

04:09.120 --> 04:09.870
So we should get

04:09.870 --> 04:11.070
whatever I type in here.

04:11.970 --> 04:12.870
There we are, 42.

04:17.810 --> 04:21.290
We can use a loop with an iterator to read multiple input.

04:22.610 --> 04:25.610
The usual question arises. How do we know when to stop?

04:26.510 --> 04:28.910
The way this works is actually rather clumsy.

04:30.350 --> 04:34.250
When there is no more input to read, the iterator will be empty.

04:34.790 --> 04:39.020
And then we have to compare the iteartor against an empty iterator.

04:40.250 --> 04:41.900
So how do we get an empty iterator?

04:42.320 --> 04:44.810
We do that by not binding it to any stream.

04:45.950 --> 04:51.800
So here we have an iterator, which can read strings but is not bound to any input stream.

04:56.300 --> 04:58.550
So in fact, we need two input iterators.

04:58.940 --> 05:05.600
One to read the data and an empty one to compare against. And then we have a loop where we compare

05:05.600 --> 05:06.740
the two iterators.

05:08.910 --> 05:12.060
If there is some data to read, then this will not be empty.

05:12.510 --> 05:15.990
So they will be not equal, and we go into the loop.

05:16.920 --> 05:23.340
We can dereference the iterator. That will give us the data that we read from the keyboard, and then we

05:23.340 --> 05:29.190
can store that somewhere. And then we can increment the iterator, so that it will move the stream marker

05:29.190 --> 05:30.270
to the next position.

05:30.660 --> 05:33.420
So that is now ready to read the next int from the keyboard.

05:34.200 --> 05:35.370
And then this goes on.

05:35.850 --> 05:39.210
And then when we read the end of input, this iterator will be empty.

05:39.600 --> 05:42.210
And it will compare equal to this one, and the loop will end.

05:45.000 --> 05:46.200
So let's try this out.

05:46.560 --> 05:50.310
We have our two iterators, the one to read data and the empty one.

05:50.880 --> 05:53.790
We have a vector where we are going to store all the data that we read.

05:54.660 --> 05:55.710
Then we have our loop.

05:56.730 --> 06:00.600
Is there any data in this iterator, or is it empty?

06:01.440 --> 06:07.770
And then in the loop, we dereference the iterator to get the data that we have read, and we increment

06:07.770 --> 06:08.640
the iterator.

06:08.940 --> 06:13.170
So we are ready to read the next int. And this will continue, until we read the end of input.

06:13.890 --> 06:18.630
And then, at the end, we have a range-for loop. And this will print out all the elements of the vector,

06:18.900 --> 06:21.060
which should contain all the data that we have just read.

06:26.580 --> 06:28.380
So I need to enter some numbers here...

06:32.140 --> 06:33.160
End of input...

06:33.640 --> 06:34.210
So there we are.

06:34.450 --> 06:37.750
We do get all the numbers that I entered, in the order that I entered them.

06:38.320 --> 06:44.380
So the control Z is of input and then the input iterator is equal to this empty iterator.

06:47.790 --> 06:50.820
So what is the point of having these stream iterators?

06:51.300 --> 06:54.740
Well, we can actually make the input-output statement a lot more concise.

06:54.750 --> 06:55.560
We could actually do

06:56.210 --> 06:56.550
this...

07:00.700 --> 07:04.330
Now we have just a single line which will read in data.

07:04.720 --> 07:08.590
So that is very concise. And I hope it still works...

07:12.010 --> 07:12.340
Yes!

07:13.480 --> 07:19.750
Always a worry when doing live coding! The other advantage is we can use these with standard algorithms,

07:19.750 --> 07:20.950
which we are going to look at later.

07:21.310 --> 07:28.030
(Sorry, more teasers!) These algorithms can do various things with containers such as transforming them,

07:28.570 --> 07:32.200
and you can copy the results into another container.

07:32.200 --> 07:34.510
So you just given an iteraator to the start of that container.

07:35.110 --> 07:40.900
If instead you give an output stream operator, then the result of that operation will be displayed

07:40.900 --> 07:41.500
on the screen.

07:42.130 --> 07:47.050
So if you want to check that your program is doing the right thing, you just need to change an

07:47.050 --> 07:47.440
iterator.

07:47.740 --> 07:49.450
You do not need to write lots more code.

07:51.040 --> 07:52.480
Okay, so that is it for this video.

07:52.900 --> 07:53.740
I will see you next time.

07:53.740 --> 07:56.050
But meanwhile, keep coding!
