They also convert.
So, constructors of a single argument
give you a prescription for basically a static cast.
So if I have a prescription from an end type to a point,
unless we take an integer value and convert it to a point, or a double value.
So any time I have a signature of a single argument that's a different
type from the object being constructed,
I'm also providing in C++ terms, a conversion operation.
Also the other thing that we can find that good programmers will do was
when they have constructors, especially when they're debugging cuz they may want
to avoid this for efficiency purposes, they can put in checks for correctness.
By that I mean the constructors can make sure that
when they initialize state, when they give values to members,
that those values represent legal values in the range that they want.
So if you're thinking of an experiment in which you are working
with liquid water, and you need to initialize its temperature.
Well we know in fahrenheit, that liquid water is between 32 degrees
and 212 degrees below it freezes, above it boils.
So if we were to assign a temperature to the liquid water widget, and
it was somehow out of that range, we know we've given it a legal initialization.
So it's also the possibilities in object-oriented programming,
using constructors to test consistency, coherence,
the fact that legal values were provided in the initialization.
Now, you're coming from the C community.
In the C community, when you wanted to manage the heap, again,
hopefully this is review for you, you used malloc, sometimes calloc.
Malloc was a memory allocator found in the C standard library.
The operating system provided you the bytes.
Why did you do that?
Well, you may have needed something dynamically in the computation.
The typical reason to use calloc() or
malloc() was I don't know how much data I'm gonna process.
I have a very large file.
The first entry of the file tells me how much data is sitting in the file.
So, it tells me I need to process
400,000 social security numbers.
Now I need something that can store 400,000 Social Security numbers.
Well, that means they need a very large array.
So, dynamically, during the computation, by calling malloc or
calloc, I can access the heap.
Assigned to a pointer, which we could think of as a base pointer,
that much memory, and then use the dynamically allocated object.
And then, good programmers don't allow for memory leaks.
And so when I no longer need that memory, I would deallocate it,
and the standard way I deallocate and C is to use free.
unless you're using much older style stuff which you would have a special reason for,
with the keywords new and delete, and the keywords new and
delete provide memory management operators,
heap management built into the C++ system.
Now, this heap is dynamically allocated memory, but
unlike Java's not garbage collected automatically, so you have to be
very careful, more sophisticated than you would be in other languages.
Great memory management involves automatic garbage collection.
What's the upside to it?
The downside's obvious, you can get memory leaks and
you have to do more complicated coding.
The upside is you can be more efficient.
See here is some simple uses of going through the heap.
We basically have, two forms,
two critical forms of the use of new and
the symmetrical use of delete.
One is to get an array of items, which is gonna be very often the case.
So if we look at this, we have a pointer type.
It's base pointer is char star, pointer to char,
and I want some dynamically
assigned value, size might be gotten from some other part of the computation.
So maybe I have a text that has a million characters in it.
I need to process a million characters.
Sizes value is a million.
New is gonna go to the heap, give me an address,
that address is gonna be the base address for the million characters assigning task.
Finally want a single only want a single element of
that type initialized then I can do it with new event and
then in this case, nine would be the value stored.
However, destruction is typically much more trivial.
Typically destruction has nothing to do with uninitialization,
it has to do with retrieving largely memory for the object.
The memory for the object might have been automatically allocated on the stack.
In which case we may not have an automatic,
we may not need to write our own restructor.
But anytime we're using new we will immediately think about
wanting a restructor.
Anytime we use resources system limited resources such as heat memory.
We would wanna call a destructor.
And the destructor has special syntax as well.
And the critical part of the special syntax is the tilde.
So if we had a deallocation for point, it would be ~point.
And we cant overload the signature as we can,
we can have multiple constructors, but we can't have multiple destructors.
Destructors don't get called with arguments.
So the destructor always has the empty or void argument list.
there was a colleague from another university who came around and
gave a talk on his research.
And he had also decided to use C++.
He had previously been using C, and he liked all the new stuff.
So we had this very complicated set of routines and
he was dynamically allocating lots of memories throughout.
And I was still a relative novice and
I was worrying about memory leaks.
So I asked him, well, what do you do about writing about your destructors and
making sure everything's working properly, and
he said I never worry about the destructors, I don't write them.
However, if you're using large amounts of memory and you're frequently going
to the operating system, it could easily slow down what you're doing.
So you really want to, if you're a high quality C++ programmer,
get into the habit of properly writing your destructors.
That's just a very important and useful skill.
So let's see a widget and which memory allocation is important.
It wasn't important in the way we defined point.
But here's a classical data structure.
We see in the slide the section in the text.
So if you wanna reference the text, go and look for
a single list element in the text, it's in page 168 and certainly you've all had
In your background, some programming of a single link list.
So recall.
You'll find that there, of course, other things.
If you wanted you could also have a doubly linked list
that has other navigational possibilities.
You'll see that when we take up the topic of the standard template library.
That list in the standard template library is indeed a doubly linked list.
Now if we start building a list it will turn out
that we wanna call the destructor to return or
to delete the box cars So
delete is gonna call a special method.
You might call it an auxiliary method.
And that auxiliary method is gonna race through the structure, and as it
races through the structure, it's gonna return each element back to the heap.
We start by building a new S list element, so that comes off the heap.
When we use new, when we use the operation
new, largely this will work, but if for
some reason there is exhaustion we will get an exception thrown.
In modern C++11,
that exception is going to be a standard exception, bad allocation.
position and then the new list.
And then we update the head.
So if we had a list head that conceptually pointed at something
where we had stored character, let's say
a new element, a new slist element in which the object,
the data being stored, is the character b.
And this was pointing to what was in effect,
the older s list that had a in it.
So that's.
And if my little boxes that I drew worked right, would work right.
I think I've tested this.
You can test this and see that it indeed works.
And just for purposes of playing around with the stuff and
seeing how it works, I'm going to use this during debuggings,
so I know when the destructor is called.
So this is very useful if
you're having trouble having a good intuition about how this happens.
It's very worth writing that out so
you can see dynamically when you run the program.
When the destructor will be invoked.
This will get printed to your screen and you can try and
figure out when this will be invoked.
And then there's this auxiliary function which I haven't shown you
how to write yet, which should march through the list performing deletions.