Lecture 18 | Programming Abstractions (Stanford)
-
0:00 - 0:08
-
0:08 - 0:12This presentation is delivered by the Stanford Center for Professional
-
0:12 - 0:16Development.
-
0:22 - 0:26Okay. Well welcome, welcome. We got a couple parents who have braved the
-
0:26 - 0:29other activities of Parents Weekend to come here, so thank you for coming to see what
-
0:29 - 0:32it is that we do here in
-
0:32 - 0:36CS106B. We are still in the process of grading the midterm. In fact, most of our grading, we're planning on
-
0:36 - 0:40taking care of tomorrow, no, Sunday, in some big, massive grading sessions. So with any
-
0:40 - 0:42luck, if it all goes well, we'll actually have them
-
0:42 - 0:45ready to go back on Monday, but if somewhere it turns into some disaster, it may take us a
-
0:45 - 0:48little longer, but hopefully. That's the plan.
-
0:48 - 0:51So I'm gonna finish up a couple slides from last time,
-
0:51 - 0:54and then I'm gonna mostly go on to do some code with you together.
-
0:54 - 0:56But I just wanted to
-
0:56 - 0:56
-
0:56 - 1:00try to give you some perspective on the value of abstraction and the idea of an
-
1:00 - 1:03abstract data type, or an ADT, and why
-
1:03 - 1:07this is such a powerful and important concept in management of complexity.
-
1:07 - 1:09So we saw this, for example,
-
1:09 - 1:13in those first couple assignments that the client uses classes as
-
1:13 - 1:14an abstraction.
-
1:14 - 1:18You have the need to manage something that has a queue-like behavior: first in,
-
1:18 - 1:19first out.
-
1:19 - 1:23So what you want is something that you can put things in that will enforce that:
-
1:23 - 1:26put things at the end of the line, always return to the head of the line.
-
1:26 - 1:29And that how it managed what it did and what went on behind the scenes
-
1:29 - 1:33wasn't something we had to worry about or even concern ourselves with. And in
-
1:33 - 1:36fact, even if we wanted to, we couldn't muck around in there. Like
-
1:36 - 1:39it wasn't our business, it was maintained privately.
-
1:39 - 1:44And that is a real advantage for both sides, right? That the client
-
1:44 - 1:47doesn't have to worry about it and can't even get in the way of us, that we
-
1:47 - 1:50can work independently and get our things done.
-
1:50 - 1:54And so one sort of piece of terminology we often use here, we talk about this wall of
-
1:54 - 1:55abstraction.
-
1:55 - 1:57That there is kind of a
-
1:57 - 1:58real
-
1:58 - 2:00block
-
2:00 - 2:04that prevents the two of us from interfering with each other's process, as
-
2:04 - 2:06part of, you know, combining to build a program together.
-
2:06 - 2:10And there's a little tiny chink in that wall that we call the interface.
-
2:10 - 2:13And that's the way that you speak to the stack and ask it to do things on your
-
2:13 - 2:16behalf, and it listens to your requests and performs them.
-
2:16 - 2:19And so if you think about the lexicon class, which we used in the Boggle and
-
2:19 - 2:22in the recursion assignment that managed a word list,
-
2:22 - 2:26the abstraction is, yeah, you say, ''Is this word in there? Add this word to it. Load
-
2:26 - 2:29the words from a file.'' How does it store them? How does it do stuff? Did anybody
-
2:29 - 2:33go open up the lexicon.cpp file just to see?
-
2:33 - 2:34Anybody who was curious? And
-
2:34 - 2:37what did you find out? I just -
-
2:37 - 2:40I
-
2:40 - 2:40think
-
2:40 - 2:44it ended up in there [inaudible]. You ended up in there and when you got in there, what did you decide to do?
-
2:44 - 2:45Leave. Leave.
-
2:45 - 2:48Yeah. Did anybody else open it up and have the same sort of reaction? Over
-
2:48 - 2:49here,
-
2:49 - 2:54what did you think? I didn't really understand. Yeah. And what did you see? It was a mess. It was a mess. Who wrote that code? My, gosh, she should
-
2:54 - 2:57be fired.
-
2:57 - 3:00It's scary. It does something kind of scary. We'll talk about it. Actually, at the end, we'll come back here because I think it's actually
-
3:00 - 3:02a really neat class to study.
-
3:02 - 3:04But in fact, like you open it up and you're like,
-
3:04 - 3:09''I don't want to be here. I want to use a word list. Let me close this file and let me go back to word list. Add word,
-
3:09 - 3:11contains word, okay.''
-
3:11 - 3:14And you're happy about that. Right? It does something very complex that turns out to
-
3:14 - 3:18be very efficient and optimize for the task at hand. But back to Boggle,
-
3:18 - 3:20you don't want to be worrying about that; you got other things on your
-
3:20 - 3:25plate and that's a fine place to just poke your nose right back out of. So if you haven't had a
-
3:25 - 3:28chance to look at it, because we will talk about it later, but the person who wrote it,
-
3:28 - 3:30was a crummy commoner. I'm just
-
3:30 - 3:32saying
-
3:32 - 3:36that they would definitely not be getting a check-plus on style, so.
-
3:36 - 3:38So I drew this picture. It's like this wall. Right?
-
3:38 - 3:42So when you made a lexicon, you say, ''Oh, I want a lexicon. Add this word. Add that word. Does it
-
3:42 - 3:44contain this word?''
-
3:44 - 3:47And that there is this big wall that - and you think of what's on the other side as a black box. The
-
3:47 - 3:50black box is the microwave that you push buttons and food gets hot. How does
-
3:50 - 3:53it really work? Ah, you know, who knows.
-
3:53 - 3:55You don't open up the back. You don't dig around in it.
-
3:55 - 3:58And this little chink here, that's the interface. And the
-
3:58 - 4:01lexicon provides a very small interface, if you remember, adding the words, checking
-
4:01 - 4:04contains word and prefix, reading
-
4:04 - 4:07the words from a file, really not much else beyond that.
-
4:07 - 4:11And then now what we're starting to think about is, ''Well, what's this other side look like?'' What goes over
-
4:11 - 4:13here
-
4:13 - 4:15is that there is this implementer
-
4:15 - 4:18who does know the internal structure. Who does know what shenanigans are being
-
4:18 - 4:21pulled on that inside, who does have access to that private data,
-
4:21 - 4:25and who, upon request when you ask it add a word or look up a word or look up a
-
4:25 - 4:29prefix, internally trolls through that private information and returns
-
4:29 - 4:31information back to the client,
-
4:31 - 4:35having mucked around in those internals. So when you say add a word,
-
4:35 - 4:38maybe what its got is some array with a count of how many words are
-
4:38 - 4:41used, and it sticks it in the next slot of the array
-
4:41 - 4:43and updates its counter.
-
4:43 - 4:46And we don't know what it does but it's not really our business as the client, but the
-
4:46 - 4:47implementer has
-
4:47 - 4:48kind of the full
-
4:48 - 4:50picture of that.
-
4:50 - 4:53And then over here on this side, if the client attempts to do the kind of things
-
4:53 - 4:57that are really implementer specific, it tries to access directly the num words
-
4:57 - 4:58and the words array
-
4:58 - 5:01to go in and say, ''Yeah, I'd like to put pig in the array. How about I do this? How
-
5:01 - 5:04about I change the number of words? Or how about I stick it in the slot at the beginning
-
5:04 - 5:06and overwrite whatever's there.''
-
5:06 - 5:09That an attempt to do this
-
5:09 - 5:12should fail. It should not compile because these fields,
-
5:12 - 5:14that are part of the lexicon,
-
5:14 - 5:17should have been declared private to begin with,
-
5:17 - 5:20to make sure that that wall's maintained. Everything that's private is like
-
5:20 - 5:24over here on this side of the wall,
-
5:24 - 5:27inaccessible outside of that. And
-
5:27 - 5:30so why do we think this is important?
-
5:30 - 5:34Of all the ideas that come away from 106B, I think this is one of the top
-
5:34 - 5:38three is this idea of abstraction. We actually even call the whole class
-
5:38 - 5:39Programming Abstractions.
-
5:39 - 5:40Because
-
5:40 - 5:45that the advantage of using this as a strategy for solving larger and
-
5:45 - 5:49more complicated problems is that you can divide up your tasks.
-
5:49 - 5:52That you can say this is an abstraction, like a word list, and kind of have it be as fancy as
-
5:52 - 5:54it needs to be behind the scenes
-
5:54 - 5:56but very easy to use from the outside.
-
5:56 - 5:59So that makes it easy for me to write some piece and give it to you
-
5:59 - 6:01in a form that's easy for you to incorporate.
-
6:01 - 6:04We can work on our things without stepping on each other. As you get to
-
6:04 - 6:06larger and larger projects
-
6:06 - 6:07beyond this class,
-
6:07 - 6:09you'll need ways of making it so three people can work together without
-
6:09 - 6:12stepping on each other's toes the whole time. And classes provide a really good
-
6:12 - 6:15way of managing those boundaries
-
6:15 - 6:16to keep each other
-
6:16 - 6:18out of each other's hair.
-
6:18 - 6:21And there's a lot of flexibility
-
6:21 - 6:24given to us by this. And we're gonna see this actually as we go forward, that we can talk
-
6:24 - 6:25about what a vector is.
-
6:25 - 6:29It keeps things in index order. Or a stack is, it does LIFO.
-
6:29 - 6:30But there is no guarantee there about
-
6:30 - 6:34how it internally is implemented, no guarantee expressed or implied, and
-
6:34 - 6:37that actually gives you a lot of flexibility as the implementer.
-
6:37 - 6:40You can decide to do it one way today, and if upon later learning about some
-
6:40 - 6:43other new technique or some way to save memory or time,
-
6:43 - 6:45you can swap it out,
-
6:45 - 6:47replace an implementation with something better,
-
6:47 - 6:51and all the code that depends on it shouldn't require any changes.
-
6:51 - 6:54That suddenly add word just runs twice as fast or ten times as fast,
-
6:54 - 6:57would be something everybody could appreciate without having to do anything in their own
-
6:57 - 7:00code to take advantage of that.
-
7:00 - 7:01So these are good things to know.
-
7:01 - 7:05So what I'm gonna do actually today is I'm gonna just stop doing slides, because I'm sick of doing
-
7:05 - 7:08slides. We do way too many slides; I'm bored with slides.
-
7:08 - 7:11And what I'm gonna do is I'm gonna actually go through the process of
-
7:11 - 7:13developing vector
-
7:13 - 7:15from just the ground up.
-
7:15 - 7:16So my plan here is to say
-
7:16 - 7:17our goal is to make
-
7:17 - 7:19the vector abstraction
-
7:19 - 7:23real, so to get dirty, get behind the scenes and say we know what vector is. It
-
7:23 - 7:24acts like an array. It
-
7:24 - 7:26has these indexed
-
7:26 - 7:29slots. It's this linear collection. It lets you put things anywhere you like in
-
7:29 - 7:30the vector. We're gonna
-
7:30 - 7:33go through the process of making that whole thing.
-
7:33 - 7:35And I'm gonna start
-
7:35 - 7:39at the - with a simple form that actually is not templatized and then I'm gonna
-
7:39 - 7:42change it to one that is templatized. So we're gonna see kind of the whole process from
-
7:42 - 7:44start to end. So
-
7:44 - 7:48all I have are empty files right now. I have myvector.h and myvector.cpp that
-
7:48 - 7:51really have sort of nothing other than sort of boilerplate stuff in them.
-
7:51 - 7:54So let me look at myvector.h to start with.
-
7:54 - 7:58So I'm calling this class myvector so that it doesn't confuse with the existing
-
7:58 - 8:00vector class, so that we have that name there.
-
8:00 - 8:05And I'm gonna start by just putting in
-
8:05 - 8:06the
-
8:06 - 8:09simple parts of the interface, and then we'll see how many other things we
-
8:09 - 8:12have time to kind of add into it. But I'm gonna get the kinda basic skeletal functions
-
8:12 - 8:15down and show how they get implemented, and then we'll see what else we'll try.
-
8:15 - 8:19So having the size is probably pretty important, being able to say, ''Well how many things will I
-
8:19 - 8:22put in there,'' get that back out,
-
8:22 - 8:23being able to add an element.
-
8:23 - 8:27And I'm gonna assume that right now the vector's gonna hold just scranks.
-
8:27 - 8:29Certainly that's not what we're gonna want in the long run, but I'm just gonna pick something
-
8:29 - 8:32for now so that we have something to practice with.
-
8:32 - 8:36And then I'm gonna have the get at,
-
8:36 - 8:38which give it an index and return something. Okay,
-
8:38 - 8:41so I think these are the only ones I'm gonna have in the first version.
-
8:41 - 8:47And then the other ones, you remember, there's like a remove at, there's an insert at,
-
8:47 - 8:47there's an
-
8:47 - 8:55overloaded bracket operator, and things like that I'm not gonna show right away. Question? [Inaudible]. Oh yeah, yeah. This is
-
8:55 - 8:58actually you know kind of just standard boilerplate for C or C++
-
8:58 - 9:01header files. And you'll see this again and again and again. I should really have pointed
-
9:01 - 9:02this out at some point along the way
-
9:02 - 9:08is that the compiler does not like to see two definitions of the same thing, ever.
-
9:08 - 9:11Even if those definitions exactly match, it just gets its
-
9:11 - 9:15total knickers in a twist about having seen a class myvector, another
-
9:15 - 9:16class myvector.
-
9:16 - 9:18And so if you
-
9:18 - 9:21include the header file, myvector, one place and you include it some other place, it's gonna end up
-
9:21 - 9:24thinking there's two myvectors classes out there and it's gonna have a problem.
-
9:24 - 9:28So this little bit of boilerplate is to tell the compiler, ''If you haven't already
-
9:28 - 9:32seen this header, now's the time to go in there.'' So this ifindex, if not
-
9:32 - 9:34defined, and then the name there is something I made up, some symbol name
-
9:34 - 9:36that's unique to this file. When I say,
-
9:36 - 9:38''Define that symbol,'' so
-
9:38 - 9:41it's like saying, ''I've seen it,'' and then down here at the very bottom, there's an end if
-
9:41 - 9:43that matches it. And so,
-
9:43 - 9:44in the case where we have -
-
9:44 - 9:47this is the first time we've seen the file it'll say, ''If not to define the symbol it's
-
9:47 - 9:48not.''
-
9:48 - 9:51It'll say, ''Define that symbol, see all this stuff, and then the end if.'' The second time
-
9:51 - 9:54it gets here it'll say, ''If not define that symbol, say that symbol's already defined,'' so it'll skip
-
9:54 - 9:59down to the end if. And so, every subsequent attempt to look at myvector
-
9:59 - 10:00will be passed over.
-
10:00 - 10:03If you don't have it, you'll get a lot of errors about,
-
10:03 - 10:05''I've seen this thing before. And it looks like the one I saw before but I don't like
-
10:05 - 10:06it. You
-
10:06 - 10:08know smells suspicious to me.''
-
10:08 - 10:13So that is sort of standard boilerplate for any header file is to have this
-
10:13 - 10:16multiple include protection on it. Anything else you
-
10:16 - 10:18want to ask about the - way in the back? Why
-
10:18 - 10:20would it look at it multiple times, though?
-
10:20 - 10:23Well because sometimes you include it and sometimes - for example, think about genlib. Like I might
-
10:23 - 10:25include genlib but then
-
10:25 - 10:27I include something else that includes genlib. So there's these ways that
-
10:27 - 10:29you could accidentally get in there more than once,
-
10:29 - 10:32just because some other things depend on it, and the next thing you know. So
-
10:32 - 10:34it's better to just have the header file never
-
10:34 - 10:38complain about that, never let that happen, than to make it somebody else's responsibility
-
10:38 - 10:44to make sure it never happened through the includes.
-
10:44 - 10:45So I've got five
-
10:45 - 10:48member functions here that I'm gonna have to implement.
-
10:48 - 10:52And now I need to think about what the private data, this guy's gonna look like. So
-
10:52 - 10:55now, we are the low-level implementer.
-
10:55 - 10:58We're not building on anything else right now, because myvector is kind
-
10:58 - 11:00of the bottommost piece of things here.
-
11:00 - 11:05We've got nothing out there except for the raw array to do the job for us. So
-
11:05 - 11:06typically, the most
-
11:06 - 11:07
-
11:07 - 11:08compatible
-
11:08 - 11:12mechanism to map something like vector onto is the array. You know it has
-
11:12 - 11:16contiguous memory, it allows you to do direct access to things by index,
-
11:16 - 11:19and so that's where we're gonna start. And we'll come back and talk about that, whether
-
11:19 - 11:23that's the only option we have here. But what I'm gonna put in here
-
11:23 - 11:24is a pointer
-
11:24 - 11:25to
-
11:25 - 11:26
-
11:26 - 11:27a string, or
-
11:27 - 11:31in this case it's gonna be a pointer to a string
-
11:31 - 11:34array. And so in C++ those both look the same, this says arr is a single pointer that points
-
11:34 - 11:35to
-
11:35 - 11:38a string in memory, which in our situation is actually gonna be a whole sequence
-
11:38 - 11:41of strings in memory kind of one after another.
-
11:41 - 11:44The array has no knowledge of its length
-
11:44 - 11:47so we're gonna build is using new and things like that. It will not know how big it is.
-
11:47 - 11:50It will be our job to manually track that.
-
11:50 - 11:52So I'm gonna go ahead and have
-
11:52 - 11:55two fields to go with it, and I'm gonna show you why I have two in a
-
11:55 - 12:00minute. But instead of having just a length field that says the array is this long,
-
12:00 - 12:02I'm actually gonna track two integers on it
-
12:02 - 12:05because likely the thing I'm gonna do with the array is I'm gonna allocate it to a
-
12:05 - 12:07certain size and then kind of fill it up.
-
12:07 - 12:09And then when it gets
-
12:09 - 12:13totally filled, then I'm gonna do a process of resizing it and enlarging it.
-
12:13 - 12:15And so, at any given point, there may be
-
12:15 - 12:18a little bit excess capacity, a little slack in the system. So we might start by
-
12:18 - 12:20making it ten long
-
12:20 - 12:21and then fill it up,
-
12:21 - 12:24and then as we get to size 10, make it 20 or something like that.
-
12:24 - 12:27So at any point, we'll need to know things about that array: how many of
-
12:27 - 12:31the slots are actually used, so that'll be the first five slots are in use; and then
-
12:31 - 12:33the number of allocated will tell me how many other - how many
-
12:33 - 12:37total slots do I have, so how many slots can I use before
-
12:37 - 12:37I
-
12:37 - 12:40will have run out of space.
-
12:40 - 12:42Both of those. Okay,
-
12:42 - 12:45so there's my interface. So these things all public because anybody can use
-
12:45 - 12:46them;
-
12:46 - 12:49these things private because they're gonna be part of my implementation; I don't want anybody mucking with
-
12:49 - 12:50those
-
12:50 - 12:53or directly accessing them at all,
-
12:53 - 12:55so I put them down there. All
-
12:55 - 12:57right, now I go to myvector.cpp.
-
12:57 - 13:01So it includes myvector.h, so that it already has seen the class interface so it knows
-
13:01 - 13:04when we're talking about when we start trying to implement methods on the myvector
-
13:04 - 13:06class. And I'm
-
13:06 - 13:07gonna start with
-
13:07 - 13:10myvector's constructor,
-
13:10 - 13:13and the goal of the constructor will be to setup the instance variables of this
-
13:13 - 13:17object into a state that makes sense.
-
13:17 - 13:18So what I'm gonna choose to do
-
13:18 - 13:24is allocate my array to some size. I'm gonna pick ten. So
-
13:24 - 13:28I'm gonna say I want space for ten strings.
-
13:28 - 13:31I want to record that I made space for ten strings so I know the num
-
13:31 - 13:33allocated, the size of my array right now is ten,
-
13:33 - 13:37and the number used is zero.
-
13:37 - 13:39So that means that when someone
-
13:39 - 13:46makes a call, like a declaration, that says myvector V, so if I'm back over here in my main. Say
-
13:46 - 13:49myvector V,
-
13:49 - 13:54but the process of constructing that vector V will cause the constructor to get
-
13:54 - 13:58called, will cause a ten-member string element array to get allocated out in the
-
13:58 - 13:58heap
-
13:58 - 14:01that's pointed to by arr, and then it will set those two integers to know that there's ten
-
14:01 - 14:03of them and zero of them are used.
-
14:03 - 14:07So just to kind of all as part of the machinery of declaring, the
-
14:07 - 14:11constructor is just wired into that so we get setup, ready to go, with some empty
-
14:11 - 14:16space set aside.
-
14:16 - 14:18So to go with that, I'm
-
14:18 - 14:22gonna go ahead and add the destructor right along side of it,
-
14:22 - 14:26which is I need to be in charge of cleaning up my
-
14:26 - 14:28dynamic allocation. I
-
14:28 - 14:30allocated that with the new bracket,
-
14:30 - 14:33the new that allocates out in the heap that uses the bracket form has a
-
14:33 - 14:37matching delete bracket that says delete a whole array's worth of data, so not just
-
14:37 - 14:40one string out there but a sequence of them.
-
14:40 - 14:43We don't have to tell it the size; it actually does - as much as I said, it doesn't
-
14:43 - 14:47its size. Well somewhere in the internals, it does know the size but it never
-
14:47 - 14:49exposes it to us. So in fact, once I delete [inaudible] array,
-
14:49 - 14:52it knows how much space is there to cleanup. Yeah?
-
14:52 - 14:54Are you just temporarily
-
14:54 - 14:58setting it up so the vector only works on strings? Yes, we are. Okay. Yes. We're gonna
-
14:58 - 14:59come back and fix that, but
-
14:59 - 15:02I think it's easier maybe to see it one time on a fixed type and then say, ''Well, what happens when you
-
15:02 - 15:05go to template? What things change?'' And we'll see all the places that we have to make
-
15:05 - 15:08modifications.
-
15:08 - 15:11So I have myvector
-
15:11 - 15:13size.
-
15:13 - 15:17Which variable's the one that tells us about size?
-
15:17 - 15:20I got none used. I got none allocated. Which is the right one? Num
-
15:20 - 15:24used. Num used, that is exactly right. So num allocated turned out to be something we only will
-
15:24 - 15:29use internally. That's not gonna - no one's gonna see that or know about it, but it is -
-
15:29 - 15:33the num used tracks how many elements have actually been put in there. Then
-
15:33 - 15:35I write
-
15:35 - 15:39myvector add.
-
15:39 - 15:42So I'm gonna write one line of code, then I'm gonna come back and think about it for a
-
15:42 - 15:44second. I could
-
15:44 - 15:45say
-
15:45 - 15:49arr num
-
15:49 - 15:50used ++ = S, so tight little line that
-
15:50 - 15:54has a lot of stuff wrapped up in it.
-
15:54 - 15:55Using
-
15:55 - 15:59the brackets on the dynamic array here are saying, ''Take the array
-
15:59 - 16:03and right to the num used slot, post-incrementing it so it's a slide effect.'' So if
-
16:03 - 16:08num used is zero to start with, this has the effect of saying array of,
-
16:08 - 16:13and then the num used ++ returns the value before incrementing. So it evaluates to zero,
-
16:13 - 16:17but as a slide effect the next use of num used will now be one. So that's exactly
-
16:17 - 16:22what we want, we want to write the slot zero and then have num used be one in subsequent usage.
-
16:22 - 16:25And then we assign that to be S, so it'll put it in the right spot of the array. So once num
-
16:25 - 16:27used is five, so that
-
16:27 - 16:31means the zero through four slots are used. It'll write to the fifth slot and then
-
16:31 - 16:35up the num used to be six, so we'll know our size is now up by one.
-
16:35 - 16:41What else does add need to do? Is it good? Needs to make sure that we have that [inaudible]. It'd
-
16:41 - 16:43better
-
16:43 - 16:44make sure we have some space.
-
16:44 - 16:48So I'm gonna do this right now. I'm gonna say if num used
-
16:48 - 16:50is equal to num allocated, I'm gonna raise an error. I'm
-
16:50 - 16:56gonna come back to this but I'm gonna say -
-
16:56 - 16:57or
-
16:57 - 17:00for this first pass, we're gonna make it so it just doesn't grow. Picked some arbitrary size, it
-
17:00 - 17:04got that big, and then it ran out of space. Question?
-
17:04 - 17:07So when the - for the
-
17:07 - 17:09vector zero, first time it gets called it's actually gonna
-
17:09 - 17:11be placed in index one of the array?
-
17:11 - 17:16So it's in place of index zero. So num used ++, any variable ++ returns the - it
-
17:16 - 17:20evaluates to the value before it increments, and then as a side effect, kind of in the next
-
17:20 - 17:23step, it will update the value. So there is a difference between
-
17:23 - 17:26the ++ num used and the num ++ form.
-
17:26 - 17:28Sometimes it's a little bit of an obscure detail we don't spend a lot of time on, but
-
17:28 - 17:30++ num says
-
17:30 - 17:33first increment it and then tell me what the newly incremented value is.
-
17:33 - 17:36Num ++ says tell me what the value is right now and then, as a side effect, increment it
-
17:36 - 17:41for later use. So the num used gets changed in that? It does get changed in that expression, but the
-
17:41 - 17:46expression happened to evaluate to the value before it did that change.
-
17:46 - 17:49Question? And
-
17:49 - 17:54is it really necessary to have myvector:: or is - Oh yeah, yeah, yeah, yeah. - there any way for - So if I take this out,
-
17:54 - 17:55and I could show you what happens if I do
-
17:55 - 17:59this, is what the compiler's gonna think that is, is it thinks, ''Oh, there's just a function
-
17:59 - 18:03called size that take the arguments and returns them in.'' And it doesn't exist in any
-
18:03 - 18:05context; it's just a global function.
-
18:05 - 18:08And then I try to compile it, if I go ahead and do it,
-
18:08 - 18:11it's gonna say, ''Num used? What's num used? Where did num used come from?''
-
18:11 - 18:14So if I click on this it'll say, ''Yeah, num used was not declared in this scope.'' It has no idea where that
-
18:14 - 18:18came from. So there is no mechanism in C++ to identify this as being a
-
18:18 - 18:21member function other than scoping it with the right names. You say this is
-
18:21 - 18:23the size
-
18:23 - 18:25function
-
18:25 - 18:27that is part of the myvector class. And now
-
18:27 - 18:31it has the right context to interpret that and it knows that when you talk about num used,
-
18:31 - 18:34''Oh, there's a private data member that matches that. That must be the receiver's
-
18:34 - 18:37num used.'' So
-
18:37 - 18:38one other
-
18:38 - 18:42member function we got to go,
-
18:42 - 18:45which is the one that returns,
-
18:45 - 18:47of I do this,
-
18:47 - 18:49it almost but not quite,
-
18:49 - 18:51looks like what I wanted. So I
-
18:51 - 18:53say return arrays of index.
-
18:53 - 18:56They said get in the next and returned the string that was at that index.
-
18:56 - 19:03Is there anything else I might want to do here? Check and see if the index is [inaudible]. Well, let me
-
19:03 - 19:05check and see if that index is valid.
-
19:05 - 19:06Now, this is one of those cases where it's like you
-
19:06 - 19:10could just sort of take the stance that says, ''Well, it's not my job.'' If you ask me to get you
-
19:10 - 19:14know something at index 25, and there are only four of them, that's your own fault and you
-
19:14 - 19:14deserve
-
19:14 - 19:16what you get.
-
19:16 - 19:18And that is certainly
-
19:18 - 19:21the way a lot of professional libraries work because this, if I added a step here
-
19:21 - 19:24that does a check, it means that every check costs a little bit more.
-
19:24 - 19:26When you go in to get something out of the vector, it's gonna have to look and
-
19:26 - 19:28make sure you were doing it correctly.
-
19:28 - 19:31And there are people who believe that if it's like riding a motorcycle without a helmet,
-
19:31 - 19:32that's your own
-
19:32 - 19:33choice.
-
19:33 - 19:35We're gonna actually bullet proof;
-
19:35 - 19:36we're gonna make sure
-
19:36 - 19:39that the index
-
19:39 - 19:41isn't whack.
-
19:41 - 19:45And I'm gonna go ahead and use my own size there. I'm gonna say if the index is less zero or it's greater
-
19:45 - 19:47than or equal to, and I'm gonna use size.
-
19:47 - 19:52I could use num used there but there are also reasons that if I use my own member functions
-
19:52 - 19:55and then later somehow I change that name or I change how I calculate the
-
19:55 - 19:59size, let's say I change it to where I use a linked list within an array and I'm managing the size
-
19:59 - 20:00differently,
-
20:00 - 20:03that if I have used size in this context, it will just change along with that
-
20:03 - 20:06because it's actually depending on the
-
20:06 - 20:08other part of the interface that I'll update.
-
20:08 - 20:09And so I'm gonna go ahead and do that
-
20:09 - 20:12rather than directly asking my variable. I'll say if that happens I say error, out of bounds.
-
20:12 - 20:15And on
-
20:15 - 20:18that, that error will cause the program to halt right down there, so I don't have to worry about
-
20:18 - 20:21it, in that case, getting down to the return. So I feel
-
20:21 - 20:22okay about this.
-
20:22 - 20:25Not too much code to get kind of a little bit of something up and
-
20:25 - 20:26running here.
-
20:26 - 20:39Let's go over and write something to test. Add Jason, and here we go. Okay, so I
-
20:39 - 20:41put some things in there and I'm
-
20:41 - 20:43gonna see if
-
20:43 - 20:50it'll let me get them back out.
-
20:50 - 20:51And
-
20:51 - 20:54before I get any further, I might as well test the code I have. Right?
-
20:54 - 20:58This is - one of the things about designing a class is it's pretty hard to write
-
20:58 - 21:02any one piece and test it by itself because often there's a relationship: the constructor
-
21:02 - 21:04and then some adding and then some getting stuff back out.
-
21:04 - 21:07So it's a little bit more code than I typically would like to write and not have
-
21:07 - 21:10a chance to test, having all five of these member functions kind of at first.
-
21:10 - 21:11So
-
21:11 - 21:14if I run this test and it doesn't work, it's like well which part what was wrong? Was the
-
21:14 - 21:17constructor wrong? Was the add wrong? Was the size wrong? You know there's a bunch of
-
21:17 - 21:19places to look, but
-
21:19 - 21:22unfortunately, they're kind of all interrelated in a way that makes it a little hard to have them
-
21:22 - 21:23independently
-
21:23 - 21:26worked out. But then subsequent thing, hopefully I can add the like the
-
21:26 - 21:28insert at method without
-
21:28 - 21:33having to add a lot more before I test.
-
21:33 - 21:37Okay. So I run this guy and it says Jason, Illia, Nathan. Feel good, I feel good,
-
21:37 - 21:41I feel smart.
-
21:41 - 21:42Put them in, in that order. See
-
21:42 - 21:44me get them out in that order. I might
-
21:44 - 21:46try some things that I'm hoping will cause my thing
-
21:46 - 21:48to blow up.
-
21:48 - 21:53Why don't I get at ten? Let's see, I
-
21:53 - 21:55like to be sure,
-
21:55 - 21:59so I want you to tell me what's at the tenth slot in that vector.
-
21:59 - 22:02And it's, ooh, out of bounds, just like I was hoping for.
-
22:02 - 22:05Oh, I like to see that. Right?
-
22:05 - 22:07What happens if I put
-
22:07 - 22:10in
-
22:10 - 22:11enough strings
-
22:11 - 22:12that I
-
22:12 - 22:16run out of memory? And we talked about a thing - it's set it to be ten right now. Why don't I just make it
-
22:16 - 22:19smaller, that'll way it'll make it easier for me. So I say, ''Oh how
-
22:19 - 22:21about this?'' I'm
-
22:21 - 22:23only gonna make
-
22:23 - 22:26space for two things. And it just:
-
22:26 - 22:30error, out of space. Right? That happened before it got to printing anything. It tried to add the first one. It
-
22:30 - 22:33added the second one. Then it went to add that third one and it said, ''Oh okay, we run out of space. We
-
22:33 - 22:35only had space for two set aside, you
-
22:35 - 22:40asked me to put a third in. I had no room.''
-
22:40 - 22:42So at least the kind of simple behaviors that I put in here seem to kind of
-
22:42 - 22:46show evidence that we've got a little part of this up and running.
-
22:46 - 22:48What I'm gonna fix first is this out of space thing.
-
22:48 - 22:54So it would be pretty bogus and pretty unusual for a
-
22:54 - 22:56collection class like this to have some sort of fixed limit.
-
22:56 - 22:59Right? It wouldn't - you know it'd be very unusual to say well it's always gonna hold exactly 10
-
22:59 - 23:02things or 100 things or even a 1,000 things. Right?
-
23:02 - 23:05You know one way you might design it is you could imagine adding an
-
23:05 - 23:07argument to the constructor that said, ''Well, how many things do you plan on putting in
-
23:07 - 23:11there? And then I'll allocate it to that. And then when we run out of space, you know you're hosed.''
-
23:11 - 23:14But certainly a better strategy that kind of solves more general case problems would
-
23:14 - 23:16be like, ''Oh let's grow.
-
23:16 - 23:20When we run out of space, let's make some more space.'' Okay,
-
23:20 - 23:23let's think about what it takes to make more space in
-
23:23 - 23:24using pointers.
-
23:24 - 23:31So what a vector really looks like
-
23:31 - 23:33is it has three fields,
-
23:33 - 23:34the arr,
-
23:34 - 23:39the num used, and the num allocated. When
-
23:39 - 23:43I declare one, the way it's being setup right now, it's over here and it's allocating space
-
23:43 - 23:45for
-
23:45 - 23:47some number, let's say it's ten again,
-
23:47 - 23:48and then marking it as zero.
-
23:48 - 23:53Then as it fills these things up, it puts strings in each of these slots and it
-
23:53 - 23:58starts updating this number, eventually it gets to where all of them are filled.
-
23:58 - 24:02That when num used equals num allocated, it means that however much space I set
-
24:02 - 24:05aside, every one of those slots is now in use.
-
24:05 - 24:08So when that happens, it's gonna be time to make a bigger array.
-
24:08 - 24:11There is not a mechanism in C++ that says take my array and just make
-
24:11 - 24:13it bigger where it is.
-
24:13 - 24:16That the way we'll have to do this is, we'll have to make a bigger array, copy over
-
24:16 - 24:17what we have,
-
24:17 - 24:18and then,
-
24:18 - 24:22you know, have it add it on by making a bigger array full of space. So what we'll do is we'll make
-
24:22 - 24:23something that's like
-
24:23 - 24:27twice as big, I'm just gonna draw it this way since I'm running out of board space,
-
24:27 - 24:31and it's got ten slots and then ten more. And
-
24:31 - 24:36then I will copy over all these guys that I have
-
24:36 - 24:38up to the end,
-
24:38 - 24:40and then I have these new spaces at the end.
-
24:40 - 24:41And so I will have
-
24:41 - 24:44to reset my pointer to point to there,
-
24:44 - 24:49update my num allocated, let's say to be twice as big or something,
-
24:49 - 24:52and then delete this old region that
-
24:52 - 24:54I'm no longer using.
-
24:54 - 24:57So we're gonna see an allocate, a copy, a delete,
-
24:57 - 25:00and then kind of resetting our fields
-
25:00 - 25:01to know what we just did.
-
25:01 - 25:05So I'm gonna make a private helper to do all this, and
-
25:05 - 25:12I'll just call that enlarge capacity here. Question? Is this like [inaudible]? Well
-
25:12 - 25:14it is - it can be, is the truth.
-
25:14 - 25:16So you're getting a little
-
25:16 - 25:18bit ahead of us. But in the sense that like,
-
25:18 - 25:20you know, if the array has a thousand elements
-
25:20 - 25:23and now we got to put that thousand-first thing in, it's gonna take
-
25:23 - 25:26all thousand and copy them over and enlarge the space.
-
25:26 - 25:30So in effect what is typically an O of one operation, just tacking something on
-
25:30 - 25:34the end, every now and then is gonna take a whole hit of an end
-
25:34 - 25:37operation when it does the copy. But
-
25:37 - 25:39one way to think about that is that is
-
25:39 - 25:42every now it's really expensive but kind of if you think of it across the whole
-
25:42 - 25:45space, that you got a - let's say you started at 1,000 and then you
-
25:45 - 25:46doubled to 2,000, that
-
25:46 - 25:48the first 1,000 never paid that cost.
-
25:48 - 25:51And then all of a sudden one of them paid it but then now you don't pay it again for
-
25:51 - 25:55another 1,000. But if you kind of divided that cost, sort of amortized it across all
-
25:55 - 25:56those adds,
-
25:56 - 25:57that it was a -
-
25:57 - 25:59it didn't change the overall constant running time.
-
25:59 - 26:02So you have to - you kind of think of it maybe in the picture. It does mean every now and
-
26:02 - 26:05then though one of them is gonna surprise you with how slow it is, but
-
26:05 - 26:06
-
26:06 - 26:07hopefully that's
-
26:07 - 26:12few and far between, if we've chosen our allocation strategy well.
-
26:12 - 26:15So I'm gonna say - actually, I'm gonna do this. I'm gonna call this
-
26:15 - 26:17thing actually double capacity.
-
26:17 - 26:21So one strategy that often is used is you could go in little chunks. You could go like
-
26:21 - 26:23ten at a time all the time.
-
26:23 - 26:24But
-
26:24 - 26:27if the array's gonna get very big,
-
26:27 - 26:30going by tens will take you a lot of time. You might sort of use sometimes the indication of, ''Well
-
26:30 - 26:33how big is it already?'' Then if that's about the size it seems to be, why don't we go ahead
-
26:33 - 26:34and just double.
-
26:34 - 26:36So if we start at 10,
-
26:36 - 26:39you know, and then we go to 20, then we go to 40, then we to 80, then
-
26:39 - 26:42as we get to bigger and bigger sizes, we'll make the kind of assumption that: well,
-
26:42 - 26:45given how big it is already, it's not - it wouldn't surprise us if it got a lot bigger. So
-
26:45 - 26:48let's just go ahead and allocate
-
26:48 - 26:50twice what we have as a way of kind of
-
26:50 - 26:54predicting that it's pretty big now, it might get even bigger in the future. That
-
26:54 - 26:55isn't necessarily
-
26:55 - 26:58the only strategy we could use, but it's one that actually often makes
-
26:58 - 27:01pretty decent sense. And then at any given point, you'll know that the vector will
-
27:01 - 27:03be somewhere between
-
27:03 - 27:05full and half capacity,
-
27:05 - 27:07is what you're setting up for.
-
27:07 - 27:10So let's do this.
-
27:10 - 27:12Oops, it's not ints;
-
27:12 - 27:14string bigger equals,
-
27:14 - 27:18and I make a new string array that is num allocated times two,
-
27:18 - 27:22so twice as big as the one we have.
-
27:22 - 27:30And now I go through and I copy. I'm
-
27:30 - 27:34copying from my old array to my bigger one,
-
27:34 - 27:37all of num used. In this case, num used and num allocated are exactly the same thing, so. And
-
27:37 - 27:38then I'm
-
27:38 - 27:43gonna reset my fields as needed. I'm gonna delete my old array because I'm
-
27:43 - 27:45now done with it. I'm gonna
-
27:45 - 27:49set my pointer to this, so that's doing pointer assignment only. Right? So I deleted
-
27:49 - 27:52the old space, I've copied everything I needed out of it, I'm
-
27:52 - 27:54now resetting my pointer to the bigger one,
-
27:54 - 27:56and then I'm setting my num allocated
-
27:56 - 28:00to be
-
28:00 - 28:01twice as big,
-
28:01 - 28:05num used doesn't change. Okay,
-
28:05 - 28:06so
-
28:06 - 28:09went through the process of building all these things. And as noted, that is gonna
-
28:09 - 28:11cost us something
-
28:11 - 28:15linear in the number of elements that we currently have, so.
-
28:15 - 28:19So this guy is intended to be a private method.
-
28:19 - 28:22I don't want people outside of the vector being able to call this, so I'm actually
-
28:22 - 28:24gonna list this
-
28:24 - 28:27in the private section. It's not as
-
28:27 - 28:29common that you'll see member functions listed down here. But in this case, it's
-
28:29 - 28:32appropriate for something that you plan to use internally as a helper but you don't want
-
28:32 - 28:39anybody outside just to be calling double capacity when they feel like it.
-
28:39 - 28:41Question? So normally [inaudible] an array, you couldn't actually
-
28:41 - 28:45declare a size like that, though, right, with a variable?
-
28:45 - 28:48You know I don't understand the question. Try that again. You
-
28:48 - 28:52know in this case to enlarge it, you use a
-
28:52 - 28:53variable as the - for the
-
28:53 - 28:57size of the array. When you normally declare an array, you couldn't do that, right? Well if
-
28:57 - 29:03you did it - It has to be a constant. So like if you used this form of an array, you know,
-
29:03 - 29:05where you declared it like this. Did you see what I just did?
-
29:05 - 29:05Yeah. Yeah.
-
29:05 - 29:06That way won't work,
-
29:06 - 29:10right? That way is fixed size, nothing you can do about it. So I'm usually totally the
-
29:10 - 29:14dynamic array at all times, so that everything - So you do it when you're declaring it on a heap?
-
29:14 - 29:15Yes. Okay.
-
29:15 - 29:19Yes, exactly. All I have in the - stored in the vector itself is a pointer to an
-
29:19 - 29:22array elsewhere. And that array in the heap gives me the flexibility to make it as big as
-
29:22 - 29:26I want, as small as I want, to change its size, to change where it
-
29:26 - 29:29points to, you know all the - the dynamic arrays typically just give you a lot more flexibility
-
29:29 - 29:32than a static array. That's really stack heap. It is. Array is a
-
29:32 - 29:35stack heap thing. When you put on the stack, you had to say how big it is at compile time
-
29:35 - 29:38and you can't change it. The heap let's you say, ''I need it bigger, I need it smaller, I need to
-
29:38 - 29:40move it,''
-
29:40 - 29:44in a way that the stack just doesn't give you that at all.
-
29:44 - 29:47So when I go back to myvector.cpp, the place I want to put in my
-
29:47 - 29:54double capacity here is when num used is equal to num allocated,
-
29:54 - 29:58but what I want to do is call double capacity there.
-
29:58 - 30:02After I've done that, num allocated should've gone up by a factor of two.
-
30:02 - 30:04Space will be there at that point. I know that num used is a
-
30:04 - 30:08fine slot to now use to assign that next thing. So whenever we're out of space, we'll
-
30:08 - 30:10make some more space.
-
30:10 - 30:13And so I'm gonna - right now, I think my allocated is still set at two. That's a fine place.
-
30:13 - 30:16I'd like it to be kind of small because I'd like to test kind of
-
30:16 - 30:18the -
-
30:18 - 30:25some of the initial allocations. So I'll go ahead and add a
-
30:25 - 30:28couple more people so I can see that I know that - at that point, if I've gotten to
-
30:28 - 30:32five, I'm gonna have to double once and then again to get there.
-
30:32 - 30:37And let's, I'll take out my error case here, see that I've managed
-
30:37 - 30:38to
-
30:38 - 30:40allocate and move stuff around.
-
30:40 - 30:42Got my five names back out
-
30:42 - 30:46without running into anything crazy, so that makes me feel good about what I got
-
30:46 - 30:49there. So
-
30:49 - 30:53I could go on to show you what insert and remove
-
30:53 - 30:53do; I think
-
30:53 - 30:57I'm probably gonna skip that because I'd rather talk about the template thing. But I could
-
30:57 - 31:01just tell you - I could sketch the [inaudible]: what does insert at do, what does remove at do?
-
31:01 - 31:04Basically, that they're doing the string - the array shuffling for you. If you say
-
31:04 - 31:08insert at some position, it has to move everything down by one and then
-
31:08 - 31:11put in there. Whereas at is actually just tacking it onto the end of the existing
-
31:11 - 31:12ones.
-
31:12 - 31:16The insert and remove have to do the shuffle to either close up the space or open up a space.
-
31:16 - 31:21They'll probably both need to look at the capacity as well. That the - if you're
-
31:21 - 31:25inserting and you're already at capacity, you better double before you start. And then the
-
31:25 - 31:28remove at, also may actually want to have a shrink capacity. Where when we realize
-
31:28 - 31:31we previously were allocated much larger and we've gotten a lot smaller, should we
-
31:31 - 31:35take away some of that space. A lot of times the implementations don't bother
-
31:35 - 31:38with that case. They figure, ''Ah, it's already allocated, just keep it around. You
-
31:38 - 31:41might need it again later.'' So it may be that actually we just leave it over-allocated,
-
31:41 - 31:44even when we've deleted a lot of elements, but
-
31:44 - 31:47if we were being tidy we could take an effort there.
-
31:47 - 31:50What I want to do is switch it to a template. So if you have questions
-
31:50 - 31:53about the code I have right here, now would be
-
31:53 - 31:55a really good time to ask before I start
-
31:55 - 31:57mucking it up. Way in the back? [Inaudible].
-
31:57 - 32:00I will. You know that's a really good idea because if I - at this point, I'll
-
32:00 - 32:03start to change it and then it's gonna
-
32:03 - 32:06be something else before we're all done. So let me
-
32:06 - 32:09take a snapshot of what we have here
-
32:09 - 32:12so that I - before I destroy it.
-
32:12 - 32:14Question? When does the deconstructor
-
32:14 - 32:16get
-
32:16 - 32:19called? Okay, so the destructor gets called
-
32:19 - 32:23in the most - there are two cases it gets called. One is when the
-
32:23 - 32:25- so the constructor gets called when you declare
-
32:25 - 32:29it, and then destructor gets called when it goes out of scope. So at the opening brace
-
32:29 - 32:32of the block where you declared it in, is when the constructor's happening,
-
32:32 - 32:35and then when you leave that. So in the case of this program, it's at the end of
-
32:35 - 32:36May,
-
32:36 - 32:38but and if it were in some called function or in the body of a for loop or
-
32:38 - 32:42something, it would get called when you enter the loop and then called as -
-
32:42 - 32:43destroyed as it left.
-
32:43 - 32:47For things that were allocated out of the heap, so if I had a myvector new myvector, it
-
32:47 - 32:50would explicitly when I called delete that thing when I was done with it.
-
32:50 - 32:55So especially when the variable that holds it is going away,
-
32:55 - 32:58right? Either because you're deleting it out of the heap or because it's going out of scope on the
-
32:58 - 33:00stack. Here?
-
33:00 - 33:04When you have string star array, arr, it's
-
33:04 - 33:07a pointer to a single string and then later you can use a new statement
-
33:07 - 33:08to
-
33:08 - 33:09link it to - Yeah. -
-
33:09 - 33:13an array. So how does it know when it - How does it know? It doesn't, is the truth, is that
-
33:13 - 33:16when you say something's a pointer to a string,
-
33:16 - 33:20the only guarantee is really there and says it's an address of someplace where a
-
33:20 - 33:23string lives in memory. Whether there's one string there or a whole sequence of strings
-
33:23 - 33:27is something you decide and you maintain, and so the compiler doesn't distinguish
-
33:27 - 33:28those two cases.
-
33:28 - 33:30It does not know that you made
-
33:30 - 33:32exactly 1 string at the other end of this or 500.
-
33:32 - 33:36And so, that's why this idea of tracking the num used and num allocated becomes our
-
33:36 - 33:39job; that they look exactly the same in terms of how it interprets them. It says, ''Well it's the
-
33:39 - 33:43address of where a string lives in memory, or maybe it's a sequence. I don't know.'' And
-
33:43 - 33:47so it lets you use the brackets and the new and stuff on a pointer without
-
33:47 - 33:51distinguishing - having any mechanism in the language to say this is a single
-
33:51 - 33:53pointer and this is an array pointer. They look the same. So
-
33:53 - 33:55you could use the bracket notion on a single pointer?
-
33:55 - 34:00You certainly can. And then - It's not a good idea but you can do it. So
-
34:00 - 34:03legally in the language, it just makes no distinction between those.
-
34:03 - 34:06They are really commingled in way that - and so that's one of the more surprising features of C
-
34:06 - 34:08and C++ and one's that a little bit hard to get your head around is
-
34:08 - 34:12it doesn't track that it's a pointer to a single thing versus a pointer to an array.
-
34:12 - 34:14That they're both just
-
34:14 - 34:15pointers and it's mine.
-
34:15 - 34:18And that allows opportunity for errors, when you mistreat them as the other type
-
34:18 - 34:21for example. Question? Can you go
-
34:21 - 34:25over in your secret view file in the [inaudible]
-
34:25 - 34:27of what's going on
-
34:27 - 34:32with [inaudible] real quick because it's just - Yeah, yeah, yeah, so let me - it was basically the thing I drew over here, but I'll do it again just to watch
-
34:32 - 34:33it,
-
34:33 - 34:35is that let's start - let's imagine I have a slightly smaller
-
34:35 - 34:37num allocated so it's a little
-
34:37 - 34:38less
-
34:38 - 34:42for me to write. So let's say that I'm gonna use a num allocated of two, so this allocates
-
34:42 - 34:43two. So
-
34:43 - 34:45when I construct it, it makes a
-
34:45 - 34:48block that holds two things and num used is
-
34:48 - 34:51zero. So I do two adds: I add A, it
-
34:51 - 34:53increments num used to one;
-
34:53 - 34:55I had B, it increments num used to two.
-
34:55 - 34:57I try to add C.
-
34:57 - 34:59It says, ''Oh, well num used equals num allocated.
-
34:59 - 35:01We're gonna go to double capacity now.''
-
35:01 - 35:07So double capacity has this little local variable called bigger.
-
35:07 - 35:08And it says bigger
-
35:08 - 35:10is gonna be something that is
-
35:10 - 35:13four strings worth in an array, so it
-
35:13 - 35:14gets four out there.
-
35:14 - 35:15It does a full loop
-
35:15 - 35:19to copy the contents of the old array on top of the initial part of this array; so it
-
35:19 - 35:22copies over the A and the B,
-
35:22 - 35:23into there.
-
35:23 - 35:27And then it goes, ''Okay, I'm done with this old part. So let me go ahead
-
35:27 - 35:30and delete that.'' And then it resets the arr to
-
35:30 - 35:34point to this new one down here, where bigger was. So now, we got to aliases of the
-
35:34 - 35:35same location.
-
35:35 - 35:38And then it sets my num allocated to say and now
-
35:38 - 35:39what you've got there
-
35:39 - 35:41is something that holds four slots.
-
35:41 - 35:45And then that used call here says, ''Okay and now writer the C into
-
35:45 - 35:48the slot at three.''
-
35:48 - 35:51So the process here is the only way to enlarge an array in C++ is to make
-
35:51 - 35:54a bigger one, copy what you had,
-
35:54 - 35:57and then by virtue of you having made a bigger array to start with, you have some more slack that
-
35:57 - 35:59you didn't have before.
-
35:59 - 36:02Daniel? How does it delete arr with a star?
-
36:02 - 36:05You know it has to do with just delete takes a pointer.
-
36:05 - 36:09It does it - so a star arr is a string, arr is a pointer to a string. So
-
36:09 - 36:13both forms of delete, delete and delete bracket - So conceptually - - a pointer. - there is a start
-
36:13 - 36:16there because it's delete - Well effectively, yeah. It's delete the thing at the other end of the pointer, really.
-
36:16 - 36:19But it's funny. Delete says
-
36:19 - 36:21take this address and reclaim its contents.
-
36:21 - 36:25And so it doesn't really operate on a string, per se, it operates on the storage
-
36:25 - 36:29where that string is. And so I don't know whether you want to call that is there an implicit star there or
-
36:29 - 36:33not, it really is about the pointer though rather than the contents.
-
36:33 - 36:38So saying that address has some memory associated with it, reclaim that memory. If I could raise -
-
36:38 - 36:39Uh-huh.
-
36:39 - 36:41So when you're
-
36:41 - 36:45first declaring or when you're making a pointer like string bigger, string star bigger,
-
36:45 - 36:47you have to declare it with
-
36:47 - 36:50the star notion. But then later on, you don't ever have to use
-
36:50 - 36:53that again? You pretty much won't see that star used again.
-
36:53 - 36:56Right? It's interesting that things like bigger sub I and erase sub I
-
36:56 - 37:00implicitly have a D reference in them. And that can be misleading. You
-
37:00 - 37:02think, ''Well how come I'm never actually using that star again on that thing to
-
37:02 - 37:04get back to the strings that are out there?''
-
37:04 - 37:08And it has to do with the fact that the bracket notation kind of implicitly D
-
37:08 - 37:09references in it.
-
37:09 - 37:13If I did a star bigger, it would actually have the effect of giving me bigger
-
37:13 - 37:16sub zero, it turns out. You can use that notation but it's
-
37:16 - 37:18not that common to need to. And
-
37:18 - 37:19so down on
-
37:19 - 37:20the last,
-
37:20 - 37:23one line up
-
37:23 - 37:24from the bottom, it says array equals bigger. You don't have to - Yeah,
-
37:24 - 37:27if you did that, if I did say - If you
-
37:27 - 37:33said array - Star arr equals star bigger,
-
37:33 - 37:35I would not be getting what I want.
-
37:35 - 37:37Right? What it would be doing is it would say
-
37:37 - 37:40follow bigger and see what's at the other end, so that would follow bigger and
-
37:40 - 37:44get that string A. And then it would say follow ARR and overwrite it
-
37:44 - 37:45with that A,
-
37:45 - 37:49so it would actually have the effect of only copying the first string
-
37:49 - 37:51from bigger on top of the first string of array. But array would still point to
-
37:51 - 37:54where it was, bigger would still point to where it was, and they would - we
-
37:54 - 37:56would've not have updated our,
-
37:56 - 38:00the pointer we really wanted to point to the new array. So
-
38:00 - 38:02there is a difference. Without the star,
-
38:02 - 38:05we're talking about the changing the pointers; with the star, we're
-
38:05 - 38:08talking about the strings at the other end. And so we're - this is a string
-
38:08 - 38:10assignment. It says assign one string to another.
-
38:10 - 38:12Without
-
38:12 - 38:15the star on it, it's like assign one pointer to another;
-
38:15 - 38:18make two pointers point to the same place. When you're done with this,
-
38:18 - 38:23bigger and arr will be aliases for the same location.
-
38:23 - 38:25That's a very important question though to get kind of
-
38:25 - 38:30what that star's doing for you. Here? After
-
38:30 - 38:34arr is bigger, can
-
38:34 - 38:35you delete bigger after that? If I deleted
-
38:35 - 38:39bigger, at that point arr is pointing to the same place. And so remember that
-
38:39 - 38:42having two or three or ten pointers all at the same place, if you delete one of them,
-
38:42 - 38:46they actually effectively are deleted. The delete really deletes the
-
38:46 - 38:49storage out here. And then if I did that, it would cause arr to then be pointing to this
-
38:49 - 38:51piece of memory,
-
38:51 - 38:54and not a good scene will come from that. It means that when it later
-
38:54 - 38:57goes back in there and starts trying to read and write to that contents at
-
38:57 - 39:00any moment it could kind of shift underneath you. You don't own it any
-
39:00 - 39:02more; it's not reserved for your use.
-
39:02 - 39:05So if we did that, we'd get ourselves into trouble. All
-
39:05 - 39:08right? So there should basically be a one-to-one correspondence between
-
39:08 - 39:10things you new and things you
-
39:10 - 39:11delete. And so
-
39:11 - 39:14in the myvector case, we newed something in the constructor that we're gonna delete in the
-
39:14 - 39:18destructor. If at some point along the way we got rid of our old one and get
-
39:18 - 39:21a new one, that's the new the one that's gonna get deleted. If we deleted it
-
39:21 - 39:23midstream here, we would just be asking for
-
39:23 - 39:29havoc when we start accessing that deleted memory. Way in the back? Is
-
39:29 - 39:31it possible to create a pointer
-
39:31 - 39:33to something -
-
39:33 - 39:37a pointer to the address that's one off the end of the original
-
39:37 - 39:42array and then just create an array just off the end there? Not really. So new doesn't let
-
39:42 - 39:43you decide where you want something.
-
39:43 - 39:45So you're point being to think,
-
39:45 - 39:48''Well I can tell you what this address is, can I just make space right there
-
39:48 - 39:53and then I won't have to copy.'' And it turns out new just doesn't give you that kind of control. You ask it for space, it
-
39:53 - 39:55finds it wherever it has and you can't -
-
39:55 - 39:58there isn't even a mechanism where you could suggest where you'd like it to be. You could say, ''Well
-
39:58 - 40:01let that place right there would be really handy. Could you please give me that one?'' It
-
40:01 - 40:02just doesn't give it you.
-
40:02 - 40:03So
-
40:03 - 40:05you're - this is the way
-
40:05 - 40:08that typically you have to manage a dynamic array. And this is actually one of the big
-
40:08 - 40:10drawbacks
-
40:10 - 40:13to continuous memory as a reason for implementing things is that the
-
40:13 - 40:16fact that it has to maintain contiguousness. Means you have to shuffle and move
-
40:16 - 40:18and copy
-
40:18 - 40:19this block
-
40:19 - 40:20
-
40:20 - 40:23without the flexibility of something like a link list where every cell is independently
-
40:23 - 40:27manipulated.
-
40:27 - 40:29There? Why does [inaudible] the delete
-
40:29 - 40:34brackets arr as delete just arr? So the difference is that if you allocated
-
40:34 - 40:38something with new string bracket, new something bracket, you need a delete bracket.
-
40:38 - 40:41If you actually use delete without the brackets, it thinks there's a single
-
40:41 - 40:42pointer and there's only one string at the other end.
-
40:42 - 40:47Where delete brackets says delete the whole gob of strings that are there.
-
40:47 - 40:49If you don't do it, it's not - the consequence is not that big;
-
40:49 - 40:52it's like some memory gets orphaned, some things don't happen. But
-
40:52 - 40:56to be totally correct, they go hand in hand: if you use new with
-
40:56 - 40:59brackets, use delete with no brackets, if you use new with brackets, use delete with brackets.
-
40:59 - 41:02So it's either both with brackets or both without.
-
41:02 - 41:04So even though arr is just point
-
41:04 - 41:07to the first place, the
-
41:07 - 41:08brackets knows the -
-
41:08 - 41:12Yeah, it does. And so that kind of makes me feel like I'm a lair because I said well the array
-
41:12 - 41:15doesn't know its length. Well it does somehow. Internally it is
-
41:15 - 41:18maintaining some housekeeping but it doesn't expose it to you.
-
41:18 - 41:21So when you say delete bracket arr it knows, ''Oh, there's a bunch of strings and I got
-
41:21 - 41:25to do a bunch of cleanup on them.'' But it doesn't ever expose that information back
-
41:25 - 41:29to you. It doesn't let you depend on it, so it's up to you to maintain that information redundantly
-
41:29 - 41:34with it. All
-
41:34 - 41:36right, let me see if I can make it a template.
-
41:36 - 41:39I probably can't do this actually fast enough to get it all done today, but we can at least get started
-
41:39 - 41:41on it.
-
41:41 - 41:42So then, I
-
41:42 - 41:46introduce a template header and
-
41:46 - 41:49I make up the name that I want here, so
-
41:49 - 41:50same class header now
-
41:50 - 41:52other than typing elem type. Then
-
41:52 - 41:55I look through my interface and I see places where I previously had said it's
-
41:55 - 41:59strings, it's strings, it's storing strings. And I say it's not actually storing strings;
-
41:59 - 42:00it's gonna store
-
42:00 - 42:02elem type things,
-
42:02 - 42:06it's gonna return elem type things
-
42:06 - 42:09and it's going to have an array of
-
42:09 - 42:11elem type things.
-
42:11 - 42:13So I think that's everything that happened
-
42:13 - 42:17to the interface. Let me see if I see any other places that I - so the
-
42:17 - 42:18interface part
-
42:18 - 42:20is kind of small.
-
42:20 - 42:23There's one other change I'm gonna have to make to it but I'm gonna come back to it. I'm gonna look
-
42:23 - 42:25at the code at the other side for a second. And I say, ''Okay, well
-
42:25 - 42:28that wasn't so bad.'' Now
-
42:28 - 42:31it turns out that it gets a little bit goopier over here
-
42:31 - 42:33because that template type name
-
42:33 - 42:38has to go on every one of these:
-
42:38 - 42:40introduce them to the template type and elem type.
-
42:40 - 42:44And now there's another place where it needs to show up.
-
42:44 - 42:49So the full syntax for this is now saying this is a template function,
-
42:49 - 42:50depending on elem type,
-
42:50 - 42:52and it's actually for the myvector
-
42:52 - 42:54who is being -
-
42:54 - 42:58we are writing the myvector constructor for something whose name is myvector
-
42:58 - 43:00angle bracket elem type.
-
43:00 - 43:02So there's gonna be a lot of this goo. Every one of these is kinda change
-
43:02 - 43:05its form, from just looking like the ordinary myvector class scope doesn't
-
43:05 - 43:06really exist any more.
-
43:06 - 43:10Myvector is now a template for which there's a lot of different class scopes,
-
43:10 - 43:13one for each kind of thing being stored. So myvector int is different than myvector
-
43:13 - 43:14string.
-
43:14 - 43:15So we say, ''Well,
-
43:15 - 43:18if you were building the myvector constructor for myvector string, it
-
43:18 - 43:21looks like this.'' Or you know
-
43:21 - 43:24having filled an elem type with those strings. So
-
43:24 - 43:30everywhere I was using string, I got to change to elem type in the body as well. And
-
43:30 - 43:32then I kind of take this guy
-
43:32 - 43:38and use it in a bunch of places. I'm gonna use it here
-
43:38 - 43:39and then I'm gonna have to do it down
-
43:39 - 43:50here, on that side, do it
-
43:50 - 43:54here, and it's gonna return something of elem type,
-
43:54 - 43:56here. It's a little bit of
-
43:56 - 43:59a mess to do this, and the code definitely gets a little bit goopier as a result
-
43:59 - 44:00of this. It doesn't
-
44:00 - 44:08look quite as pretty as it did when it wasn't a template,
-
44:08 - 44:11but it becomes a lot more useful. Okay.
-
44:11 - 44:14Then I need to look for places that I used a string.
-
44:14 - 44:17And every place where I was using string, assuming that's what I was storing, it
-
44:17 - 44:20now actually turns into elem type. So
-
44:20 - 44:23my pointers and the kind of array I'm allocating is actually now made into elem
-
44:23 - 44:24type.
-
44:24 - 44:27The rest of the code actually didn't say anything specific about what's its doing, just copying
-
44:27 - 44:30things from one array to another. And now, depending on what the arrays are, it's
-
44:30 - 44:32copying ints or strings or doubles.
-
44:32 - 44:36And then other places in the interface where I'm doing add or I'm going get at, I have to be
-
44:36 - 44:40describing the things that are coming in and out as elem type so that they can be
-
44:40 - 44:42matched to whatever the client's using. I
-
44:42 - 44:45think the rest of it looks okay. Why do you have to write
-
44:45 - 44:47template type name, and elem type above
-
44:47 - 44:50every - Because you just have to, because it's C++. Because the thing is,
-
44:50 - 44:53that piece of code is, itself, a template, so
-
44:53 - 44:56these are like little mini-templates. So that I had the interface, which said here's the
-
44:56 - 44:58template pattern for the
-
44:58 - 45:02interface, and each of these says when you're ready to make the size member function for a vector of int,
-
45:02 - 45:05it comes off this template. So this template describes what the size member function
-
45:05 - 45:09looks like for any of the myvectors you might instantiate. And it describes the
-
45:09 - 45:12template because, in fact, we need to build a new size for
-
45:12 - 45:14ints versus doubles versus strings.
-
45:14 - 45:17It's even funny because you think of my size like, ''Well size doesn't even
-
45:17 - 45:21use anything related to the elem type.'' But in fact, each of the member functions
-
45:21 - 45:25is kinda specific. It's not just a myvector size; it's the myvector int size, the
-
45:25 - 45:26myvector string size.
-
45:26 - 45:30And that for some of the member functions it's quite obvious why you need a distinct
-
45:30 - 45:33copy. Get at returns an int in some cases and a double in others;
-
45:33 - 45:36but even though ones that don't appear to have any dependence on the elem type,
-
45:36 - 45:37actually are
-
45:37 - 45:40separated into their own
-
45:40 - 45:41individual versions.
-
45:41 - 45:45So I think I got all of that fixed, and then I'm gonna have to do one thing that's gonna seem
-
45:45 - 45:49really quirky. And it is very quirky but it is C++. Let me show
-
45:49 - 45:51you what I'm gonna do.
-
45:51 - 45:59Is I'm going [inaudible] out of the project. Okay,
-
45:59 - 46:01stop compiling that.
-
46:01 - 46:01And I'm gonna change
-
46:01 - 46:12how it is that myvector gets compiled by doing this. Okay. Take
-
46:12 - 46:14a deep breath.
-
46:14 - 46:15This is really
-
46:15 - 46:18just an oddity of C++.
-
46:18 - 46:20So the situation is this: that
-
46:20 - 46:23templates aren't really compiled ahead of time,
-
46:23 - 46:25templates are just patterns.
-
46:25 - 46:26You know? They like describe
-
46:26 - 46:30a recipe for how you would build a myvector class.
-
46:30 - 46:34But you can't just compile myvector and be done with it because until the client
-
46:34 - 46:37uses it, you don't know what kind of myvectors you're building. Are they myvectors of ints
-
46:37 - 46:39or strings or pseudo structures?
-
46:39 - 46:43So it turns out that the myvector really needs to get compiled
-
46:43 - 46:46at the usage, at the instantiation. When you're ready to make a myvector of
-
46:46 - 46:50students, it then needs to see all the code for myvector so it can go build you a
-
46:50 - 46:53myvector for students on the fly.
-
46:53 - 46:56In order to see that code, it actually has to be present in a different way than
-
46:56 - 46:59most code. Most code is compiled, instead of .cpp, it just
-
46:59 - 47:02gets compiled once and once for all. The random library, random integer doesn't
-
47:02 - 47:06change for anybody usage, there's a random.cpp. It compiled the function.
-
47:06 - 47:07You're done.
-
47:07 - 47:11So the template code does not get compiled ahead of time. It doesn't get listed in the
-
47:11 - 47:13project. What happens is the .h
-
47:13 - 47:17typically has not only the interface, but actually all the code.
-
47:17 - 47:21And so the two ways to get the code in here, one way is I could've just put all the
-
47:21 - 47:24code down here. And that's the way a lot of professional code gets written, it has
-
47:24 - 47:28the interface followed by all the template code right after it. I
-
47:28 - 47:32like to keep us thinking about the interface and the implementation being
-
47:32 - 47:32separate,
-
47:32 - 47:35so I'm actually taking the interface and keeping the .h, keeping this [inaudible]
-
47:35 - 47:36over here
-
47:36 - 47:42in a .cpp. And then I'm using the #include mechanism in a very unusual way. That almost
-
47:42 - 47:45never would you want to, in a regular usage, to #include another
-
47:45 - 47:49.cpp file. For templates, we're making an exception. And we're saying, ''Well
-
47:49 - 47:53in this case, because I really need that code there,'' the #include mechanism is
-
47:53 - 47:57basically saying go take the contents of this thing and just dump it in here.
-
47:57 - 48:01It really is an include mechanism. It says, ''Go get this file and take its text
-
48:01 - 48:03contents and dump it right into this file.''
-
48:03 - 48:06So that when somebody's trying to import the myvector.h,
-
48:06 - 48:09they're getting both the interface plus all the code that we'll generate a
-
48:09 - 48:11pattern from.
-
48:11 - 48:13So this is definitely just a quirk.
-
48:13 - 48:14There's no
-
48:14 - 48:16
-
48:16 - 48:18consistency between how other languages that do stuff like this expect
-
48:18 - 48:19this.
-
48:19 - 48:22This is just unique to C++ and its compilation mechanisms that require
-
48:22 - 48:24this kind of sort of slight
-
48:24 - 48:26variation in handling.
-
48:26 - 48:29So we'll see this for all the templates we'll use is that
-
48:29 - 48:33they will not be included as normal cpp files, they will get included in the .h.
-
48:33 - 48:35And there is this exact pattern, which is
-
48:35 - 48:39reproduced for every one of the ones in the text. You'll see it on stack and queue and
-
48:39 - 48:44integer. That it becomes the kind of boilerplate we'll use when making a template. So
-
48:44 - 48:45in general, I'd say
-
48:45 - 48:49be very wary of anything that looks like this. This is not a normal thing to do
-
48:49 - 48:52and we're doing it just specifically to kind of keep up the illusion that the
-
48:52 - 48:55interface and the implementation are kept separate because there's actually
-
48:55 - 48:57some good thinking that comes from that.
-
48:57 - 49:00But the way the compiler sees it, it doesn't want them to be separate, and so
-
49:00 - 49:06we have to accommodate it with this little hack, let's say, here.
-
49:06 - 49:08So once I've done that,
-
49:08 - 49:10I go back to lecture.
-
49:10 - 49:14If I change this to be myvector string,
-
49:14 - 49:16I'm hoping
-
49:16 - 49:19that everything will still work.
-
49:19 - 49:20Which it did, kind
-
49:20 - 49:21of amazingly. Daniel?
-
49:21 - 49:23So
-
49:23 - 49:27where is the myvector.cpp file at? So it's actually just living in the same directory with this,
-
49:27 - 49:30the way myvector.h is. So typically, like your .h files are just sitting in the directory - .cpp is sitting in the
-
49:30 - 49:34same directory. That's where it's gonna look for it when it
-
49:34 - 49:38goes #including is in the kind of local contents. But like
-
49:38 - 49:39where is that? Like is it in
-
49:39 - 49:42resources? No, it's just - if you look - you know this is the directory I have, this
-
49:42 - 49:43is the
-
49:43 - 49:47contents of my, you know all my files, my project files, where the thing gets dumped. Oh, okay. It's just sitting there with all
-
49:47 - 49:50the code.
-
49:50 - 49:53And I should be able to
-
49:53 - 49:57change this now to put some numbers in
-
49:57 - 50:03and have it do both. I just did it
-
50:03 - 50:05with strings and now I'm gonna do it with ints.
-
50:05 - 50:06And
-
50:06 - 50:10voila, we now have something that holds ints. So a certain
-
50:10 - 50:12amount of goo that went from
-
50:12 - 50:14the simple form to the template form,
-
50:14 - 50:18but a lot of power gained. Suddenly we took this thing that was one purpose,
-
50:18 - 50:21that held strings only, and you just made it to where it can hold anything you
-
50:21 - 50:23can think of to stick in there
-
50:23 - 50:24
-
50:24 - 50:26by making
-
50:26 - 50:28little machinations in the
-
50:28 - 50:29syntax there.
-
50:29 - 50:34So we'll see a lot more of this. It's not the first, nor the last, syntax that - for templates that we're gonna be playing
-
50:34 - 50:36with, but that will be next week. Come to Cafe with me, if you
-
50:36 - 50:45got some time. Otherwise, I will see you on Monday.
- Title:
- Lecture 18 | Programming Abstractions (Stanford)
- Description:
-
Lecture 18 by Julie Zelenski for the Programming Abstractions Course (CS106B) in the Stanford Computer Science Department.
Julie introduces the 'implement vector' and discusses ADTs (abstract data types) in more detail. She then develops a Vector from the ground up, explaining each step as she goes.
Complete Playlist for the Course:
http://www.youtube.com/view_play_list?p=FE6E58F856038C69CS 106B Course Website:
http://cs106b.stanford.eduStanford Center for Professional Development:
http://scpd.stanford.edu/Stanford University:
http://www.stanford.edu/Stanford University Channel on YouTube:
http://www.youtube.com/stanforduniversity/ - Video Language:
- English
- Duration:
- 50:54
N. Ueda edited English subtitles for Lecture 18 | Programming Abstractions (Stanford) | ||
Eunjeong_Kim added a translation |