Week 6 - Memory Management and Rule of Three
Learning objectives
Upon finishing this week, you should be able to:
- Accurately describe how a program is using the stack, heap and pointers
- Use destructors and copy constructors appropriately in classes
- Describe and diagram the difference between a deep and a shallow copy
- Write simple container classes that manage dynamic memory
Suggested pacing
Day 1
- Using Valgrind
Day 2
- Dynamic Memory, Pointers & Arrays
- Pointer Drawing WS
Day 3
- Destructors, Copy Constructors, Assignment Operator
- CPPLab - Copy Constructors & Assignment Operators
Day 4
- Garbage collection and smart pointers
Activity Outline
Valgrind
There is a fabulously useful tool called Valgrind that helps you find memory related errors and leaks. Unfortunately, it is not well supported for Windows or Mac. So you will either need to set up a virtual linux machine (likely easiest for Windows), use a similar but different tool (likely easiest for Macs), or log into a Linux based server provided by the CS department (will work for anyone, but makes it harder to access the tool quickly.)
Use this Valgrind Guide to explore the options and try out Valgrind.
This video shows how and why we use Valgrind (but does not replace the written instructions):
Anytime your code is graded from now on in CS162 and 260, we will likely be running Valgrind to look for memory issues. Thus you should be using it to make sure there aren't any hidden issues. Code can look like it is working fine and be full of memory leaks and other issues!
Dynamic Memory
Review chapter 11.9 & dynamic memory:
Do the PointerDrawing WS from the classroom files link. This video demonstrates how to do the problems:
Pointers and Arrays
Pointers and arrays are surprisingly interchangeable in C/C++.
Read 11.5, 11.8.
Watch this video (related code is in the cs162 repository):
Memory Management in Classes
Read 11.12-11.15 on using classes to manage memory.
This video explains the core ideas of these sections. You can find the Polygon code in the DestructorCopyConstructor example in the Github repository:
Tackle the first two problems in the Rule of 3 CPPLab (don't do the Assignment operator problem yet)
Assignment Operator and Rule of Three
We have seen two parts of the rule of three - the idea that any class which directly manages data on the heap (stores pointers) generally needs to implement a custom destructor, copy constructor and assignment operator.
The first video is one someone else made that reviews the need for the rule of three. Watch it if you aren't 100% sure you have the idea. The second video is my introduction to the actual details of the assignment operator.
Finish Rule of 3 CPPLab (assignment operator problem)
Container Classes
As a wrapup, check out the SimpleIntList code sample from the github repository. It is an example of a class that manages memory to help do a job. Checking out how it works will give you a good idea how to approach this week's assignment.
Garbage collection and smart pointers
You may be starting to realize that managing memory on our own is difficult and error-prone. Fortunately, it is not something that we always have to do. Many programming languages provide tools to help remove some of the burdens - as you work on the assignment for the week you can take some time to learn at a conceptual level about these tools. (You will NOT be using either of these tools this week). This video introduces the big ideas:
If you want more details, you can check out these sources:
- geeksforgeeks.com page on Garbage collection
- geeksforgeeks.com page on Smart Pointers
Extra (Optional) Info
Additional Rule of 3 Source
Here is another good video on the rule of three focusing on just the concepts, not code:
Rule of Five
In modern C++ there are two other operators related to the rule of three: the move constructor and move assignment operator. They are used to write efficient code, but are not necessary. Failing to use them does not cause the same kind of errors that forgetting to implement a destructor or custom assignment operator does. This level of efficiency is the kind of thing a professional C++ developer should care about - but for now we have better uses for your brain cells. If you want to learn more about them check the learncpp.com coverage of move constructor and move assignment operator.
Inheritance and Memory
If you are managing resources in classes that use inheritance, you have to worry about child classes correctly calling parent class assignment operators and copy constructors. You also have to make sure that the destructor is marked virtual so that deleting an object via its pointer accesses the correct destructor. We will not be dealing with these issues in this class.
Rust
Rust is a programming language that uses ownership of memory as one of its core design principles. In Rust, the goal is to never have memory that is "shared". All memory is owned by exactly one reference. We may let the memory be borrowed temporarily by something like a function, but the original reference cannot use the memory while it is borrowed and the memory may only be borrowed by one reference at a time.
This video introduces this way of thinking about memory: