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.