In this video, I'd like to go over 1 of the most basic of the stl
containers, the array container.
I'll call it std array in this video, so we don't
confuse it with a raw array.
In order to use the std array container, we must include
the array header file.
The std array container allows us to create fixed size arrays of any type.
So what makes this different from a raw array, a lot.
First, it's an object type.
Std array always has its size associated with it.
Unlike a raw array, a std array doesn't decay to a pointer to
the first element of the array when we pass it into a function.
It's also very efficient.
Element access happens in constant time.
Constant time means that the time it takes to access an element
is independent of the number of elements in the container.
So if std array has 5 elements and you wanted to access 1 of them.
The time required would be the same as if it had 100,000 elements.
Also since a std array is implemented behind the scenes by
the stl as a wrapper class around a raw array, we can get access
to that raw array address if we need to and we can use it with
libraries that use raw pointers.
But the biggest benefit is that it's part of the stl, so we can use
it with iterators and algorithms.
The std array class wasn't part of the original stl.
It was added in c++11.
You should always first consider using std array in modern c++ when you
have a need for a fixed size array.
Don't use raw arrays unless you have a compelling reason to do so.
All of the stl iterators are available with std array,
and they don't invalidate.
And that makes sense because std array is a fixed size structure.
Okay, so first, let's look at a few ways to initialize std
arrays and then we'll see some of the common member methods.
Std array is a very simple template class.
Since the size of the array must be known at compile time, we have
to provide both the type we want to store in it as well as the size.
This is exactly what we did a few videos ago when we
created a my array class.
In the first example in the slide, I declared arr1 as a std array
of 5 integers, and I initialize these 5 integers to 1 2 3 4 and 5.
If we have more than 5 integers in the initializer list, we'll get an error.
If we have fewer than 5, the remaining integers omitted will be set to 0.
Now there is a quark with the initializer list.
In c++11, you need to provide double curly braces.
In c++14 and forward you don't, just a single curly brace.
So in the second example, I'm declaring stooges as
a std array of 3 strings.
And I'm initializing them to Larry Moe and Curly.
Note that I can use c-style string literals and they'll
be converted to std strings.
There's also a very handy way to assign multiple values
to an existing std array.
We can use an assignment statement and an initializer list.
This is really cool and extremely useful.
So now let's see some common methods provided by std array.
In this section, I'm not going to exhaustively go over all the methods
provided by all of the stl containers.
That would be pretty boring for me and, it would probably
be even more boring for you.
So what I want to do is I'll go over some of the most common
methods used and some of the methods particular to specific containers.
So let's start with the size method.
This method is available to all containers.
In the std array, it's pretty simple.
It's the size of the container and it's fixed.
Arrays also let us access individual array elements.
We can use either the subscript syntax or the .at method.
Now if you remember from the vector, subscript operator
does no bounds checking.
But the at method does do bounce checking, and an exception is
thrown if we're out of bounds.
You can see in the example code that arr at 0 will refer to 1 in the array
arr, and arr sub-1 refers to the 2.
The std array also provides front and back methods.
Now these methods return references to the element at the front of the
array and of the element at the back of the array, respectively.
In this example arr.front refers to the 1 and arr.back refers to the 5.
The empty method will return true if the std array is
empty and false otherwise.
This doesn't mean how many elements out of the total elements
you're using, it basically means it's the size of the array.
This is rarely ever used with std array but it is
with other stl containers.
The fill method is very handy, it fills the std array with
whatever element is provided.
Remember, I'm using ints here for these examples, but these
could be almost any data type.
We can also swap 2 std arrays of the same size and type.
All we have to do is simply call swap with 1 and pass the other in.
And finally, we can use the dot data method to get access
to the underlying raw array.
In this case, data returns the address of the raw array of integers, which
we store in a pointer variable.
As you can see, std arrays are very straightforward.
Now let's head over to the IDE and we'll see some more
examples of using std array.
Before we head off to the IDE and run some examples with the
std array, I'd like to refer you to this website and I've mentioned
this website a couple times in the course, it's cppreference.com.
I'm here in the United States, so I'm getting the english version.
I'm not sure if this is localized for other countries.
It seems like it would be because you see the EN at the beginning here.
In any case, go to cppreference.com and it's got all kinds of
good information about c++.
Up to now, we really haven't needed it too much, but with the
containers library and the stl, your algorithms and your iterators,
this is a really useful reference.
I'm right at the main page here.
And you can see the containers library is right here.
So I'll just select that, and it shows you all the containers in the stls.
For example, array that's one we're going to talk about now.
A vector, a deck, a forward list.
We'll talk about all of these in this section.
But let's just look at the array.
And this gives you a lot of really good reference and
documentation on the array.
You can see it's implemented as a template class here.
And if you scroll down just a little bit all of these containers will
talk about iterator and validation.
So if you're not sure about -- if you've got an iterator and you've
removed an item is it invalid now.
it'll say it all throughout the documentation here.
Also the other important piece are these, right here,
these member functions.
This tells you what member functions are available for
this particular container.
Now you can see here I can construct it and destruct it and so forth.
But these are the real important ones here.
This is a really simple container, the array container.
So you've got the at method, you've got the overloader subscript operator.
Notice this one does balance checking, and the operator subscript does
not, the front, the back, the data.
The same things I talked about in the slides.
We've also got iterators.
You can see all the iterators are available to us here.
And then we've got some capacity methods and the fill and the
swap that I also mentioned.
So this gives you a lot of really good information.
Now if you're not sure about what the front method does, I mean it
says here access the first element, which is makes sense right the front.
But if you want more information, you can click on here.
And not all of these things are going to be easy reads when you're first
starting out with c++, but you'll understand this soon enough and little
by little, you'll understand more and more and more, and then these
references become very, very handy.
In this case, you can see what does it do.
Well, it provides a reference to the first element.
That's kind of what I said earlier, right.
The complexity is constant time, which is cool.
Usually most of these methods will have a complexity
associated with them.
And it'll be listed here.
I mentioned before that with the stl you know what you get.
So when you're using these methods, you know their complexity.
So if you're using something that's a linear time, you'll understand that.
If it's constant time, it'll say it as well.
And then it's got usually some kind of sample code here that you
can run right inside your browser.
So it's a very handy site.
I think you're going to refer to this a lot.
When I go to the ide, I'll be playing with a lot of source code
that you can play around with and it covers the majority of these,
but obviously, it's impossible to cover them all, especially as the
containers and the algorithms and the iterators all come together, the
permutations just go skyrocketing.
So play on your own.
And go through here, study this.
This is the best way to really learn the stl, but watch the videos
first and then you'll be able to understand this a lot better.
All right, so let's head over to the IDE.
Okay, so I'm back in the IDE.
I'm in the section 20 workspace in the array project.
And what I've done is I've broken this project up into 9 test functions.
And each one of these functions is independent and deals with
specific methods or iterators or algorithms that we can really learn.
My perspective on the stl is the more examples you can see, the
better you're going to learn it.
And the more you can apply what you're learning to other examples that you haven't seen yet.
Okay, so why don't we start.
Rather than jump back and forth and running and compiling and
so forth, I've already run this.
And the output is over here on the right.
I've run all 9 functions over here on the right, and there's the output.
And what I'll do is I'll go through them, so you can
understand exactly what's going on.
This will save a little time, and that way you can stop the
video and look at them as well.
So let's start with test 1.
First thing we're going to do here is we're going to create 2 std arrays.
They're both the same size, and they're both of the same type.
So I'm creating an array right here called arr1 of 5 integers, and I'm
initializing it to 1 2 3 4 and 5.
I'm also creating array 2, same size same type, but
I'm not initializing it.
And then I'm displaying both arrays.
Now the display function is right up here.
Let me clear this and show that to you.
And the way the display functions work for std arrays, notice the parameter
right here, the parameter type.
You've got to supply the information.
So you've got to supply the type and the size.
For all it's doing is just using a range-based for loop to display it.
All right, so let's get back to this.
Let's go through test case 1 here.
So we've got those 2 arrays, arr1 arr2.
I'm displaying both of them.
They're out right here.
You can see there's my test 1 output right here.
Notice the first 1 prints out 1 2 3 4 5, exactly like we expect.
Now notice arr2, we're displaying it right here.
We've got 5 garbage values.
So nothing is initialized.
When we do something like this, we're initializing the std
array, but we're not initializing the elements of the std array.
That's important to understand.
Now we have here is a really nice way to assign a bunch
of values to a std array.
And the syntax is dead simple and it's so handy.
So what we're doing here is we're assigning 10 20 30 40 and 50 to
arr2, that's the one that had all those garbage values in it.
And then we're displaying those 2 arrays again.
So you can see them displaying right here, 1 2 3 4 5 and now 10 20 30 40 and 50,
which is really nice.
Here we're just displaying both sizes.
Now they're both the same size, right.
So we should -- we expect a 5 and a 5, and that's exactly what we get here.
They're both size 5.
Size isn't really used very often with std arrays.
The size is fixed, right.
So it is what it is.
It's right here.
But it's used a lot in other containers.
Let me clear this a little bit, and let me scroll up just a bit so we
can get to these guys right down here, the last couple of lines.
You can see here in this example that we can subscript into
arr1 or arr2 any std array.
This does not do bounce checking.
So what we're doing here is we're storing a 1000 into arr1 sub-0.
Okay, that's this guy.
We're basically replacing that 1 with a 1000.
And then over here what I'm doing is I'm replacing arr at 1 with
2000 so that would be the 2.
So I'm replacing the 2 with 2000.
This does no bounce checking, this does do bounce checking.
So if I'm out of bounds right here, I'm going to get an exception
thrown an out of range exception.
And all I'm doing now is displaying arr1, and you can
see arr1 displaying right here.
Notice the 1000 and the 2000 have been updated.
I still have the 3 4 and the 5.
And then the last 2 examples are right here at the bottom where I'm saying
what is arr.front and what is arr -- sorry, arr2.front and arr2.back.
So what's the front element of array 2, and what's the
back element of array 2.
Well, array 2 is right here.
The front element is a 10, the back element is a 50.
That's exactly what we expect.
That's exactly what prints right here.
Okay, so some really simple examples.
And again, I'm going to do a lot of examples in this section
so you can better understand how some of this stuff works.
Let's take a look at the next one now.
And you can see the output for test 2 right over here
on the right, right here.
All right, so what are we doing here, same idea.
I've got 2 arrays, array1 and array2.
I'm initializing the first one 1 to 5 and 10 20 30 40 and 50 for array2.
I'm displaying both of them.
And there they are right there, just what you would expect 1 2 3 4
5 and 10, all the way through 50.
Now I'm using the fill method.
I'm filling array1 with 0s.
And this could be any integer.
I'm just passing a 0 into it.
And again, remember, I'm using integers for these examples.
These could be almost any type.
So I'm using a 0 here.
I'm filling array1 with a 0, and then I'm displaying those guys again.
Notice how array1 right here is all 0s now.
So it's a real handy way to fill an array with whatever value we want.
Now we're coming here, and what we're saying is let's swap those 2 arrays.
I could say array1.swap array2 or array2.swap array1, right.
I mean swapping is swapping.
So in this case, I'm swapping those 2 arrays, and I'm displaying them again.
And you can see that they have indeed been swapped, right.
First it was a 0, then it was 10 to 50.
Now it's 10 to 50 and the 0s are second.
Okay, so let's move on to the third test.
And let's take a look at this one.
The results are right here.
I had another line that printed that header right here, but I removed it.
That's why you're seeing that test 3 twice.
All right, so I've got array1 1 2 3 4 5.
Again, it's a std array of 5 integers.
Now what's going on here.
The data method returns the raw pointer that points to the
behind the scenes raw array.
What happens is, remember, arr1 is an object.
So it has some data associated with it.
One of the pieces of data is 5, right.
It knows its size.
The other piece of data that it has is the actual array.
In this case, 5.
So this guy is what's returned the address of that element.
So when we say arr1.data, what we're returning is the address
of that first element in the raw array behind the scenes.
Remember, the std array is really a wrapper around a raw array.
And I'm storing that into pointer which is a pointer to an integer,
the address of an integer.
Now if I display pointer, you can see right there, that's the
memory address being displayed.
That's the memory address of that first element in the array.
Now I can change that through the pointer.
I could say dereference pointer equals 10000.
And I just put a 10000 in here.
And if I display arr1, you can see it right here, see that
10000 being updated right there.
Now you don't do this very often.
Obviously, the whole point of using a std array is not to use a raw array.
But sometimes we use libraries that use raw arrays.
So we can still use std arrays for our work.
And then when we need to pass in the raw array, we can use the data
method and send them what they want.
But we can still have the safety and ease of use on our end.
And what's really cool about using the std arrays on our end is because
they are stl containers, so we can use them with iterators, we can use
them with algorithms and so forth.
So that's that's the real power.
We'll go to test 4.
And test 4 is a real simple example.
We're going to sort this array.
It's really, really cool.
Here's the array 2 1 4 5 3.
Again, all of these are std arrays.
And I've defined this 1 to 5 integers again.
I'm displaying it right here.
And this is test 4 so you can see the output right here.
So I'm displaying array 1 2 1 4 5 3.
That's what we get right here, 2 1 4 5 3.
Then I'm sorting it.
Now this sort is an algorithm, right.
That's my sort function and it expects 2 iterators, where
do I start, where do I end.
Well, I'm starting at the beginning, and I'm ending at the end.
I'm sorting the entire array.
And then I'm displaying it.
So you can see right here it's displaying the sorted array,
1 2 3 4 5, easy as that.
All right, so let's take a look at test 5.
And for each one of these tests, I tried to add a little
bit different functionalities.
Again, the more examples, you see the better.
Hopefully, you'll start seeing the patterns of use, and it makes it
much much easier to understand.
All right, so here's test 5.
You can see the output right here is just 1 line of output.
Here's my array arr1 2 1 4 5 3.
And what we want to do is we want to find the minimum the maximum in there.
So we have an algorithm called min element, and we have
another one called max element.
It expects iterators, right, it's an algorithm.
So array1 begin array1.end.
I want to search through the entire array for the minimum element.
And this doesn't return the minimum element.
This returns an iterator to the minimum element.
So this is how you would declare that variable.
Min num is an iterator to a std array of 5 integers.
Now that's ugly, right.
That's really ugly looking code.
It's readable, but it's kind of ugly.
This is much nicer.
Let the compiler figure it out.
So I did it the long way for the minimum number.
And I did it the short way using auto for the max number.
So all I'm saying is auto max num hey compiler figure out that max number
is type based on the return here.
And I'm doing the same thing.
And remember, we get back iterators so we dereference the iterators
and we get back the min number, which in this case is 1 and the
max number which in this case is 5.
And that's exactly what we expected here.
So let's move on to test 6.
And test 6 is a real simple test.
You can see it again right over here, there's only one line of output.
There is another algorithm called adjacent find.
And what it does it searches through a container and returns the first
occurrence of 2 adjacent values.
Now these 2 adjacent values are compared, right, with the equality
operator, which we would overload if we had our own classes, but
here we're using integers again.
So you can see here it is.
Right here, I've got 2 3s, one right next to another.
That's what I expect.
So this also returns an iterator.
I'm using auto and I'm saying adjacent equals std adjacent
find from beginning to the end.
Give me the first occurrence of any 2 adjacent items.
It's possible there are no adjacent items.
So I would check if adjacent is not equal to array end, I found something.
If it is equal to array end, there were no adjacent elements.
So in this case, we found them.
And there's the iterator, which we dereference.
And you can see right here adjacent element found with value 3.
Pretty cool and pretty easy and pretty powerful as well.
Hopefully, you're starting to see the real power of the stl.
It's actually awesome.
You can do so much with it.
All right, test 7.
Here's the output for test 7 right here.
Real easy.
We're using the accumulate algorithm.
We've used this before as an example.
In order to use this, you have to include numeric.
Okay, it's not an algorithm.
It's an included numeric.
So make sure you do that.
And all it does is it accumulates from this iterator to that iterator,
and this is where it starts.
If you started at 10, it would start adding from 10.
In this case, I'm starting from 0.
What's really important here is that this type and this type and this type
are the same, so double double 0.0.
Make sure they're all the same.
Otherwise, you can run into some really, really weird little errors.
We do this.
It sums them up 1 plus 2 plus 3 plus 4 plus 5, we display it
and we get the sum is 15, which is just what we would expect.
And let's do a couple of more we're almost done with these.
Hopefully, you're following along.
I think you are because it's pretty straightforward stuff.
The last 2 we'll do is the count and then we'll do a count
if using a lambda in test 9.
So here's test 8.
This time I've got a std array of 10 integers.
And again i called it array1.
And in this case, I've got 1 2 3 4 5 6 3s.
I just want to count them.
So I'm going to use the algorithm count.
So I'm going to say std count, they always use iterators
from beginning to end.
What am I looking for, the 3.
That's it.
What do I expect back, I expect back 6, right.
I just counted them up here.
So this is an integer.
You get back the integer of the number of occurrences.
It says I found 3 6 times.
This would same thing we would expect.
And then the last one is the count if, which is very similar to count except.
It's using a predicate, and what we're going to do is we're going
to supply a lambda expression.
So here's what I've got.
I've got arr1 again is 10 integers it's just std array, and those are the
10 inches you can see them right here.
And what I want to do is I want to find out how many
numbers are between 10 and 200.
So there's 1, there's 2, there's 3, there's 4.
I don't want to include 200 in this case.
So I expect back a 4.
So what do we use we use count if.
Where do we start, at the beginning.
Where do we end, at the end.
And what's the predicate.
Well, I want to return true when x is greater than 10
and x is less than 200.
That's it.
And there's my lambda expression.
You can see my x is being passed into here for each element.
So the 1 will be passed in here as x, and we're going to check
that the 2, the 3 all the way from whatever our iterators say.
So in this case how many matches we expect, 4.
We'll display them right here and that's what you get
right there in the output.
Okay, so again, a lot of examples.
I did a lot of examples on purpose because I want you to have a lot
of examples on your end in the source code that you can play with.
And as I said, you're probably going to get tired of seeing
these examples, but the more examples you see the better.
All right, so that covers std array.
In the next video, we'll start talking about std vector, which
you know a lot about already.