Skip to content

Quiz 10 — Copying and Resource Management

Ten questions on what the compiler's default copy and move do, and on the Rule of Three, Five and Zero.

Attempt all of them closed-book, then mark yourself against the answers.

Concepts: shallow vs deep copy · copy constructor · copy assignment · move operations · Rule of Three / Five / Zero · self-assignment · moved-from state.


Q1. (MCQ) The compiler's default copy constructor for a class with an owning int* member produces:

  • A. a deep copy
  • B. a shallow copy — the pointer is copied
  • C. a compile error
  • D. a move

Q2. (true/false) A class that declares a destructor still gets a usable compiler-generated copy constructor.

Q3. (multiple-select) Which statements about the Rule of Three are true? Select all that apply.

  • A. If you write any one of the three, you likely need all three
  • B. It applies to classes that own a resource
  • C. The three are the destructor, the copy constructor and the copy assignment operator
  • D. It requires you to write a move constructor

Q4. (predict) Write the output.

#include <iostream>

class Buffer {
public:
    explicit Buffer(int n) : n_(n), data_(new int[n]) { data_[0] = 42; }
    Buffer(const Buffer& other) : n_(other.n_), data_(new int[other.n_]) {
        for (int i = 0; i < n_; ++i) data_[i] = other.data_[i];
        std::cout << "copied\n";
    }
    ~Buffer() { delete[] data_; }
    int& operator[](int i) { return data_[i]; }
private:
    int  n_;
    int* data_;
};

int main() {
    Buffer a{3};
    Buffer b = a;
    b[0] = 7;
    std::cout << a[0] << ' ' << b[0] << '\n';
}

Q5. (predict) Write the output.

#include <iostream>
#include <utility>

class Handle {
public:
    explicit Handle(int id) : id_(id) { std::cout << "open " << id_ << '\n'; }
    Handle(Handle&& other) noexcept : id_(other.id_) {
        other.id_ = -1;
        std::cout << "move " << id_ << '\n';
    }
    ~Handle() { if (id_ != -1) std::cout << "close " << id_ << '\n'; }
    int id() const { return id_; }
private:
    int id_;
};

int main() {
    Handle a{10};
    Handle b = std::move(a);
    std::cout << "a is " << a.id() << ", b is " << b.id() << '\n';
}

Q6. (debug) Why does this copy-assignment operator misbehave on x = x? Give one fix.

class Blob {
public:
    Blob& operator=(const Blob& other) {
        delete[] data_;                       // (1)
        data_ = new int[other.n_];            // (2)
        for (int i = 0; i < other.n_; ++i) data_[i] = other.data_[i];
        return *this;
    }
private:
    int  n_ = 0;
    int* data_ = nullptr;
};

Q7. (analysis) A class holds only std::string and std::vector members. Which of the five special members does it need to write, and why?

Q8. (short answer) What state is a moved-from object in, and what are you allowed to do with it?

Q9. (predict) How many times does "copy" print, and why not more?

#include <iostream>
#include <string>
#include <vector>

class Tag {
public:
    explicit Tag(std::string id) : id_(std::move(id)) { }
    Tag(const Tag& other) : id_(other.id_) { std::cout << "copy\n"; }
    ~Tag() { }
private:
    std::string id_;
};

int main() {
    std::vector<Tag> box;
    box.reserve(2);
    box.push_back(Tag{"T1"});
    box.push_back(Tag{"T2"});
    std::cout << "size " << box.size() << '\n';
}

Q10. (design) A grade book owns a dynamic array of marks and must be copyable and efficiently movable. Decide which special members you would write, and one way to need none of them.


Scoring: mark yourself with the answers, then read the self-assessment guide.