Hello again! In this video, we are going to look at insert iterators.
We have already met stream iterators.
If you assign to an output stream iterator,
this will insert data into the corresponding output stream.
The library also provides us with insert iterators. If we assign to one of these,
it will insert an element into the associated container.
There are three types of iterator which can add at different places.
One for the back, one of the front, and one which will insert at any given position.
To get an insert iterator, we need to call an inserter function.
And there is one of these for each of the iterators: back, front and arbitrary.
The arguments to the inserter call is the container.
The container object that we wish to insert the element into. And the function will return an insert
iterator, which is bound to that particular object.
The back insert iterator will add a new element at the back of the container. It will call the
push_back() function of the container.
So, obviously, this only works with containers that supports push back, and not all of them do.
The value that we are assigning will be passed as the argument to push_back().
So every time we assign to this iterator, a new element will be added at the back of the container.
And its value will be the value that we are assigning to it.
So here is an example. We start off with an empty vector.
Then we get a back insert
iterator for it. We call back_inserter() with the vector object as argument. And that will return a back
insert
iterator.
And then when we assigned to it, say 99, this will call push_back() on the vector with argument 99. If we
assign again, with 88, it will call push_back() again, with argument 88.
So we should have a vector with two elements which are 99 and 88.
And that is what we get.
So we have the empty vector.
We get a back insert iterator.
We assign to it.
And that populates the vector.
The front insert iterator is exactly the same, except it calls push_front().
Unfortunately, we do not know any containers yet, which support push_front().
Vector and string do not support it.
But if you know how to use the list or deque types, then you can try that for yourself.
With the inserter function, we need to provide a second argument, which is the position where
we want to insert the new element.
And that is just a normal positional iterator. So we can do something like this to get the second element.
An iterator to the second element.
Then we can pass that as the second argument to the inserter call.
And obviously the vector is the first argument.
And this will return an insert iterator, which will insert an element before the second element
of this vector.
So we have a vector with elements 1, 2 and 3.
We get a positional iterator to the second element of this vector, and then we pass that as the second
argument to the inserter call.
And obviously, the vector is the first argument.
Then, when we assign to this iterator, this will call the insert member function of the vector with
the position as the first argument and the value 99 as the second argument.
So this will insert a new element, with value 99, just before this
iterator.
So that is going to go just before the second element.
And then the elements of the vector will be 1, 99, 2 and 3.
OK.
One thing we need to be careful of. And this applies to insert operations generally, not just with iterators.
Looking at this code again, we have this iterator to the second element, and then we insert something
before it.
So after we do this insertion, what is the status of this iterator?
And the answer is that it is undefined. It is possibly invalid.
The reason is that the vector it may have done some internal rearrangement. It may have moved the elements
around or relocated the buffer.
So I am going to dereference it and print the results out. And let's see what happens.
So you can see, there was a bit of a pause there.
And I think that was because the program has crashed.
When I did this with gcc,
I just got completely random numbers.
So obviously it's not safe to use that iterator.
So if you have an insert operation, then any iterators or references to elements which you took before
the insert operation. [They] are no longer valid and you should not use them.
We can use insert iterators anywhere that expects a positional iterator. One use is with algorithms which
copy iterators.
So we talked about this with output streams.
You can provide an output stream iterator and it will copy the container to output.
With this one, it'll copy the container to a different container.
The advantage of using an insert iterator is that the container will always expand to make sure
it has enough room.
If you just use an ordinary iterator, then you may overflow the container. But we will look at that
in more detail, when we go into copying algorithms.
Another use for insert iterator is with stream iterators. So you can write much simpler code for
copying data from input into a container.
So let's remind ourselves how input stream iterators work.
We have an input stream iterator, which is bound to the standard input, and we have another one
which is empty.
Then we have this loop, so we compare the two iterators.
If they are different, then there is more input.
If they are the same, then we have reached the end of inputs and we can terminate our loop.
Then we dereference the input stream iterator. And that will give us the next bit of data from the
inputs. And then we increment the iterator to move on to the next word in the input.
Here we have a back insert iterator to a vector. So we have our empty vector and we have the
call to back inserter. And that is a back insert iterator.
So if we assign to that iterator, it will call push_back() on the vector. And it will append the data
to the back of the vector.
So this is reading data from the stream and appending it to the back of the vector.
And then when we reach the end of the loop, the data in the vector should be the same as the data
that was typed in at the keyboard.
So let's try this.
So... a bit of input. And there we are.
So the data that I entered in the keyboard goes straight into the vector. And that is probably a bit
simpler than using right-shift operators and calling push_back() directly.
OK, so that is it for this video.
I'll see you next time, but until then, keep coding!