OK, so welcome back to another one of these lectures about pointers and some dynamic memory stuff in
this lecture, we're going to talk about kind of some weird C++ behavioral stuff that you need to know
about to avoid kind of shooting yourself in the foot with this language, because C++ lets you do a
lot of granular level stuff and it doesn't really protect you.
Like other languages, it'll let you do some things that really just aren't OK, and it shouldn't let
you do.
But it does that to let you have control.
So you can really kind of create sticky situations for yourself, especially with these pointers and
stuff.
So what I'm going to do is I'm going to actually comment out some of this stuff down here, so I'll
just go.
Right here and just kind of block comment this out.
And what I'm going to do is make another function.
What it's going to do is return an end point here.
So I'm going to go ahead and do that.
I'm just going to call this my other function.
And what I'm going to do, though, is I'm going to make a local variable in here and I'm just going
to call this like.
I'll just call, yes, like in local bar five.
And what I'll do is I will return the address.
All right.
So I'm putting this ampersand like we were just talking about the address of the local bar right here.
And then what I'm going to do is I'm going to make another pointer in here and the integer pointer,
and I'm just going to call it main pointer equals my other function because what's going to happen is
it's going to return this address and it's going to take that address and store it in this pointer.
The real problem here, though, there is a problem and that is that or make it a local variable inside
this function and returning the address of that variable.
So the reason that that is a problem.
Is that the stat region of the memory is where this local variable is being created, it is stored there.
You remember in that lecture when we were talking about the virtual address space, the most recent
virtual address space lecture where we showed the stack growing downwards towards lower memory addresses
and we had those green boxes right, and each one was a stack frame.
Whenever a function gets called, it makes a new stack frame and those frames pile up like plates,
you know, stacks of plates growing towards lower memory and the stack is growing down.
Well, there was a stack frame for this, my other function, when it gets cold, it has a new stack
frame.
So what you can imagine is that there's all those houses on the street, right?
Before a house is even built, there still is an address for the empty lot, right?
So it's it's kind of like there was an empty lot and, you know, maybe it had some other stuff there
you don't even know, maybe there was another house there, but what happened was got rid of one house,
got rid of whatever it was there, bulldozed it, built a new house for this function, right?
New house went ahead and stored some things in that house.
Maybe, you know, there's like.
You stored.
I don't know, there's like a car in the garage, and that is this integer, right?
It's a local piece of data.
It's a local variable.
It's stored inside that house in a stack frame.
When the function is done, that stack frame, there's a good chance that stack frame gets torn down
because the operating system is managing that memory.
It does a lot of stuff, right?
It's just a complicated zone.
It's like a really busy street, which is houses going up and going down and just cars flying in and
out like all over the place, data going everywhere.
It's a real, messy zone in the operating system has like a lot of different rules that it uses to manage
that area.
So what that means is that you should always consider when the function is done.
You don't necessarily have access to this exact variable in memory anymore because it was created in
that stack frame.
And now that stack frame is not going to be the same way it was when you were inside this function.
So when the execution is flowing through this function, your program is being ran in, it's done with
that function.
This might just disappear.
It might still be there or might still disappear.
You don't know that's up to the operating system to decide, but the thing is that you shouldn't rely
on it.
And so what happens when we want to use this?
So it returns the address here that goes right here, right?
Because we called this function and it got returns down to here this address of local VAR.
That address then got saved into this point, and now we have a pointer with that address and then what
do we try and do with it?
Maybe we try and print it out, right?
Main main point here.
Print out, main pointer in line, you know, and then maybe we do something like, you know, main
pointer equals 50 or 540, I don't know.
And then we go ahead and print out mean pointer again now.
So let me go ahead and save this.
And then run this hour compiled and one, compile it.
And then what happens when we compile it so.
Let's check this out.
So what it does is it doesn't give us in error, but it gives us a warning and it's giving us a warning
about doing this right here.
So it says address of local variable returned.
So it's talking about Line 10, this local variable, which referring to my 10, but it knows that,
you know, that's going to be a problem.
But like I said, C++ is going to go ahead and let you do it.
This is just a warning.
It's not an error.
This program still compiled successfully so we can still run this executable, even though this is a
problem, you know?
This may or may not exist when we run it, this function.
When it's getting ran, you know, all this stuff will be in a stacked frame and we get torn down,
and then we're thinking that we still have access to this zone of memory expecting us to be able to
print it out.
So let's go ahead and show that we can run this.
I run it.
Nothing prints out, right?
And this might not be the case for you.
Something might print out.
You might see some numbers.
I don't really know.
Like I said, it's undefined behavior.
So what should we do if this is bad?
Then what can we do if we want to make some sort of local variable in here in this function?
But we want to be able to return it.
What would we do?
Well, like I said, the heap is a much less busy area, right?
It's not managed quite as much by the operating system.
It's a little more free.
So what we could do is return that value instead on a heap, right?
We can put this on the heap instead of putting it on the stack.
So what I could do is comment this out and kind of do a similar thing, but make it on the heap so I
could say and and then make a pointer and I could just say.
You know, I'll just call this local bar and I can say equals new and like this, and then I could say,
you know, a local bar, star, local bar I.D. reference ID, I say it's five.
And then what I could do is I could just return local bar because it's already a pointer, right?
So I could do something like this.
I would like to also show you some new syntax right here.
So if you don't want to do something like this, you can all on one line make it initialized to five.
By doing that with putting some parentheses there.
So instead of doing this extra line if you want, you can both declare this variable and then do the
new int and initialize it with the value five by putting in parentheses after the end.
So this changes stuff up, this will make it OK and won't give a warning for us, so let's go ahead
and compile this.
We notice we don't get any warning here and then let's go ahead and run it.
You notice it prints out what we expected this time.
We initialized it with five in here and we went ahead and returned this local bar.
We got the pointer and got saved in this pointer, right?
As we returned an integer pointer, it got saved in this pointer.
Remember that when we had an ampersand here before we were returning an address, but also remember
that pointers are just addresses.
That's what I said in the last tutorial, the last video I was just talking about the fact that it's
really just doing an address.
Now we're doing the same thing, but it's just we're returning explicitly the pointer, right?
We made a pointer.
We return a pointer.
The pointer is getting saved into this other pointer.
They're all the same data types.
So this is all gravy.
It's OK.
We go ahead and we print that out.
It was five, right?
So it's printing out what it was initialized to here.
We d reference it.
We change it to five hundred forty.
Then we print it out and we see this expected result here.
Why is this OK?
Well, it's because it's on the heap.
The heap is a lot more free.
It's a lot.
I would call it a more chill area, I guess, to be able to go ahead and do that and declare some variables
there without us having the problem of, like, I don't know, Stack Frame got torn down.
Who knows whether we can access this local variable anymore?
All right.
So an important point to know about using functions, returning addresses, making local variables.
C++ sometimes lets you do things that you really shouldn't be doing.
I just want to let you know that and point that out.
Another thing that we need to do is what well, we did.
We allocated this memory right?
And you may be thinking well.
It's in a local function, how do we allocate it?
We don't know where it is.
No, it's fine.
It's on the heap.
We're returning a pointer, which is just an address.
This address gets returned.
We're still able to refer to that address, except that actual memory that's at that address.
It's way over and he planned, and we still have access to that zone of memory so we can go ahead and
do a delete and we can go ahead and delete main pointer.
We didn't declare main point, right?
That's not what we declared, we declared this pointer.
And it was pointing to this piece of memory return, that pointer, that pointer got saved in here.
We printed it out.
And you may be thinking, well, we've done all this stuff with it, but why don't we have to delete
local law, Poyner?
Isn't that what we have to delete?
These things main pointer and local law pointer, they're having the same address in it, and the thing
that really matters to delete is what's at that address, so we can still follow main pointer to the
same address as local VAR, right?
And that's going to contain they're both pointing to the same region of memory.
So here, when we delete main pointer, we still solve that problem.
We still deleted the memory, the memories, the thing that we need to free up, right?
We need to unreservedly.
Right, so that can be used still.
So this is totally valid and fine to do.
The.
Local stuff in the function, like the address, you know, it can be created on the stack, but it's
really just a pointer that memory that we're referring to is actually over on the heap, right?
So just want to like really make sure that you understand the different locations that data is going
into, you know, we here, we're storing some addresses somewhere in those addresses point to other
regions of memory that store the actual data that we care about.
Right.
And since we did it this way, we didn't run into any warning.
So we don't have issues, right?
OK, so this is kind of a complex thing to wrap your head around, like I said, I'm breaking these
into kind of smaller bite sized lectures, so it's easier to, I guess, digest or ingest whatever you
will, you know, but I'm going to go ahead and in that lecture here.
So the next lecture, I can start up on another topic and I don't cluster too much complicated stuff
together.
All right.
So with that, I will see you in the next lecture.