Lecture 22: Copying Objects

Apr 3, 2024  β”‚  Last updated Apr 3, 2024 by Charlotte Curtis

HTML Slides html β”‚ PDF Slides PDF

Where we left off

  • Thinking recursively
  • Recursion with linked lists
  • Tail recursion
  • Some more examples with recursion

Textbook Chapter 14

void hanoi(int n, int src, 
           int dest, int spare) {
    if (n == 1) {
        cout << "Move disk from " << src 
             << " to " << dest << endl;
    } else {
        hanoi(n-1, src, spare, dest);
        hanoi(1, src, dest, spare);
        hanoi(n-1, spare, dest, src);
    }
}

Today’s topics

Textbook Section 11.4

Copying objects

Default copying

Case iv: Initializing an object

Default copy constructor

Copying pointer members

What if the member variable is a pointer, such as the head of a linked list?

class StringStack {
public:
...
private:
    struct Node {
        std::string data;
        Node *next;
    };
    Node *head;
};

Passing objects by value

Main takeaway: shallow copy is not enough for dynamically allocated data

Overriding the default copy constructor

Why does the parameter need to be a reference?

Implementing the copy constructor

A copy constructor for StringStack

StringStack::StringStack(const StringStack &other) {
    head = NULL;

    // copy the contents of other
    Node *curr = other.head;
    while (curr) {
        push(curr->data);
        curr = curr->next;
    }
}

Note: we can call push because it doesn’t copy a StringStack

Overriding the assignment operator

Overriding the assignment operator

Implementing the assignment operator

StringStack& StringStack::operator = (const StringStack &other) {
    if (this == &other) // check for self-assignment
        return *this;

    while (!empty()) // destroy existing data
        pop();

    Node *curr = other.head; // copy the contents of other
    while (curr) {
        push(curr->data);
        curr = curr->next;
    }

    return *this;
}

Side tangent: avoiding code duplication

The Rule of Three or “The Big Three”

Classes with dynamically allocated data should always have:

  1. A destructor to free the memory
  2. A copy constructor to make a deep copy
  3. An assignment operator to make a deep copy

If you need to write one of these, you probably need to write all three. That said, copy constructors and assignment operators are not required for assignment 4.

emoji Copying check-in 1/2

Which of the following is not a case where the copy constructor is called?

  1. Passing an object to a function by value
  2. Returning an object from a function by value
  3. Initializing an object with another instance
  4. Allocating an object dynamically with new
  5. None of the above, they all call the copy constructor

emoji Copying check-in 2/2

When dealing with classes with dynamically allocated members, the default copy constructor might:

  1. Cause a dangling pointer to be created
  2. Cause a memory leak to occur
  3. Cause a segmentation fault to occur
  4. All of the above
  5. None of the above

A (very brief) intro to Inheritance

bg right:40% 80%

Inheritance

AKA creating a new class from an existing one

What gets inherited?

private members are still private

Inheritance: main takeaway

Coming up next

And that’s all for new content!



Previous: Lecture 21: Recursion
Next: Lecture 24: The Last One