Constructors are very important. They have several functions. They initialize. We've been talking about initialization. They allocate. Especially when we get to very complex. Widgets that require going to the heap and getting memory, we'll see that there will be the use of new in those more complicated widgets. 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. And when you allocated from malloc you got a certain number of bytes off the heap. 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. Free and malloc and calloc are replaced 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. So this is one item, this is many items. And then if I deallocate an array, corresponding to the two things up there I need the special notation brackets for deallocating an array. And I don't have brackets when it's a single element. Fairly simple, but something to keep in mind. You have to make sure that you use these two items consistently. Now, we've talked a lot about constructors. Why? Almost any kind of widget has some kind of construction that it needs. It needs at a minimum, initialization. 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. And then you have your semantics. And very typically that's going to involve some form of delete. What if you forget these structures? A lot of people forget these structures. When I was first doing C++, and this was now in the 1980s, 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. And that's okay if you don't worry about memory leaks. >> Remember, memory links generally won't show up in your program malfunctioning. The memory typically gets reallocated by the operating system when your process ends. And most of these systems have that built in like a UNIX system. 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. The case of a single link list, we typically have a header pointer. We typically draw it. It's like a little train of boxes. With arrows and then it would end with something where you'd also call a no-pointer. So this would be canonically, if you study computer science, one of your classic expandable data structure, dynamic data structures. And there's a singling list. 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. So constructor, here's the default constructor. The default constructor has the head point at 0, so that's in effect the empty list. There's no little box cars to point at. 0 is the null pointer. 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. Okay. So conceptually hopefully you've seen this kind of notation, and you've done this kind of coding previously. So here's a standard list structure operation of a singly linked list is called prepend. What prepend does is it puts an element on the front of the list. On the front of the list. The underlying element here is going to be a character and. 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. And that's going to do, unless it's handled, cause an abort. So you can either handle it or cause an abort. And typically that's quite safe. Now here to do the prepend, we have to create a new header, update the header by adding the new character into the data 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 lower case a, and then this was the no list, no pointer. So we'd have a single element list. And now we want to insert or prepend the character b. We would end up with h pointing at 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 now let's look at the destructor. Okay, we have our special way of naming a destructor. It uses tilde. Only used in destructors. Otherwise we use the class name. And we're assuming this is written. In the file. So, it's not inside the scope of the class. So, that's why it's using scope resolution. 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.