← Back to 24T3

Tutorial 3: Memory, Classes II

MTRN2500 24T3


Tutorial Slides


Memory

Pointers

  1. Discuss what a pointer is. What type of data does a pointer contain? What is the size of a pointer?
  1. Complete the following simple program to demonstrate the use of pointers.
#include <iostream> int main() { int x = 10; // declare a pointer to an integer called p // assign the address of x to p // print the value of x using p // print the address of x using p }
  1. What is wrong with this program? How could we fix it using pointers?
void swap(int a, int b) { int temp = a; a = b; b = temp; } int main() { int x = 10; int y = 20; swap(x, y); // I'm expecting x to be 20 and y to be 10 std::cout << "x: " << x << ", y: " << y << std::endl; }
  1. What is -> in C++? Where might you use it?

Dynamic Memory Allocation

  1. What is the difference between stack and heap memory? How is memory managed in each? When would you use one over the other?
  1. In C, you would have used malloc() and free() to allocate and deallocate memory. What is the C++ equivalent? Refactor the following C-style program to use C++ to avoid C-style memory allocation.
#include <iostream> int main(void) { int *p = (int*)malloc(sizeof(int)); // allocate memory for an integer *p = 10; // assign a value to the integer std::cout << *p << std::endl; // print the value free(p); // deallocate the memory }
  1. Refactor the following program to use new and delete instead of malloc() and free() to dynamically allocate an array.
#include <stdio.h> #include <stdlib.h> int main(void) { int size = 0; scanf("%d", &size); // allocate memory for an array of integers int *p = malloc(size * sizeof(int)); // deallocate the memory free(p); }
  1. What keyword does C++ introduce to replace null pointers being represented with NULL ?

Smart Pointers

  1. What classes are available in the C++ Standard Library for smart pointers? What are the differences between them?
  1. What benefits do smart pointers provide over raw pointers? Discuss how issues such as memory leaks are avoided with smart pointers.
  1. Refactor the following program to use std::unique_ptr instead of raw pointers.
#include <iostream> int main() { int* p{new int{10}}; std::cout << *p << std::endl; delete p; }
  1. Convert the following program to use smart pointers (prefer std::unique_ptr over std::shared_ptr ) instead of raw pointers. The program will double free when executed.
int* ptr1{new int{1}}; int* ptr2{new int{2}}; int* ptr3{ptr2}; int var{5}; int* ptr4{new int{var}}; int* ptr5{new int{var}}; delete ptr1; delete ptr2; delete ptr3; delete ptr4; delete ptr5;

References

  1. What are references? How are they different from pointers and values?
  1. What is a possible value for x that would cause the function to crash? How can we use references to prevent this?
// given a pointer to an int, add 5 to the value void addFive(int* x) { *x += 5; }
  1. Which of the following lines of code will cause a compilation error? Why?
int x = 10; int& y{x}; // line 1 const int& z{x}; // line 2 const int a = 20; int& b{a}; // line 3 const int& c{a}; // line 4
  1. Explain why “copy constructed” is printed in the following program. How can we modify the program so that “copy constructed” is not printed?
struct Simple { Simple() { std::cout << "constructed" << std::endl; } Simple(Simple const& other) { std::cout << "copy constructed" << std::endl; } }; void foo(Simple s) { // Do something with s. } int main() { Simple s; foo(s); }
  1. Why does the compiler give a warning for the following program?
#include <iostream> int& createRef(int val) { int& ref{val}; // Create a reference to val here. return ref; // Return the reference. } int main() { int& ref{createRef(42)}; std::cout << ref << std::endl; }

Classes II

Destructors

  1. What is a destructor and how is it named? When is it called? What is the purpose of a destructor?
  1. Implement a destructor for the following class. It should perform all necessary cleanup operations.
class IntList { public: IntList(std::size_t size): mData{new int[size]}, mSize{size} {} // TODO: Implement the destructor private: int* mData; std::size_t mSize; }
  1. What is the output of the following program?
#include <iostream> class A { public: A(int a): mA{a} { std::cout << "A constructor: " << mA << std::endl; } ~A() { std::cout << "A destructor: " << mA << std::endl; } private: int mA; }; int main() { A a{1}; { A b{2}; } A c{3}; }

Operator Overloading and Friend Functions

  1. What is operator overloading? What are some operators that can be overloaded in C++?
  1. What are friend functions in C++? When would you use them?
  1. Suppose I have a class Enrolments that keeps a list of students enrolled in a course. Overload the operators specified below:
class Enrolments { public: Enrolments() = default; void addStudent(const std::string& student) { mStudents.push_back(student); } // TODO: add student to the list Enrolments& operator+=(const std::string& student); // TODO: combine the other Enrolments object's list of students with this object's list Enrolments& operator+=(const Enrolments& other); // TODO: return a new Enrolments object that contains the combined list of students friend Enrolments operator+(const Enrolments& lhs, const Enrolments& rhs); // TODO: print the list of students, separated by newline characters friend std::ostream& operator<<(std::ostream& os, const Enrolments& enrolments); private: std::vector<std::string> mStudents; };

Move and Copy

  1. What is the output of the following code?
#include <iostream> #include <string> int main() { std::string s1{"Hello"}; std::string s2{s1}; std::string s3 = s1; s1.append(" World"); std::cout << s1 << std::endl; std::cout << s2 << std::endl; std::cout << s3 << std::endl; }
  1. Implement a Vector2D class that represents a 2D vector that satisfies the interface below. Identify the copy and move constructors and the copy and move assignment operator overloads.
class Vector2D { public: Vector2D(); Vector2D(double, double); Vector2D(std::vector<double> const&); Vector2D(Vector2D const&); Vector2D(Vector2D &&); Vector2D operator=(Vector2D const&); Vector2D operator=(Vector2D &&); // Overloaded type conversion. operator std::vector<double>(); friend Vector2D operator*(Vector2D const& vec, double scalar); friend Vector2D operator+(Vector2D const& lhs, Vector2D const& rhs); private: // TODO: create your own private members here };