Skip to content

Module 9 — Challenge Problems

Open problems. More than one defensible answer exists, and the reasoning is assessed as much as the code. Each one is designed so that a quick answer is visibly insufficient.


X1 — find the ownership bug, and say how you would have caught it [L4 Analyze]

The problem. The class below was reviewed, tested, and shipped. It leaks, and it has a second defect that no sanitizer reports.

class Enrolment {
public:
    Enrolment(std::string id, Student& student, Course& course)
        : id_(std::move(id)), student_(student), course_(course) {
        course_.seatTaken();                       // (a)
    }

    ~Enrolment() { course_.seatFreed(); }

    std::vector<Grade>& grades() { return grades_; }        // (b)

    Course& course() { return course_; }                    // (c)

private:
    std::string id_;
    Student& student_;
    Course& course_;
    std::vector<Grade> grades_;
};

class Registry {
public:
    Enrolment& enrol(Student& student, Course& course) {
        enrolments_.push_back(Enrolment("E-" + std::to_string(++counter_), student, course));
        return enrolments_.back();                          // (d)
    }

private:
    std::vector<Enrolment> enrolments_;
    int counter_ = 0;
};

What a good answer contains.

  • The leak or the lifetime fault, stated as a scenario, not a category. Who is left holding a dangling reference, and what line produced it? (Two candidates: the vector reallocating while a caller holds (d)'s reference; and Enrolment's destructor running when the vector reallocates — which does free the seat and then the element is copied into the new storage — leaving the seat count inconsistent. Say which you found and how you would prove it.)
  • Defect (b), with the attack that uses it: what can a caller break that Registry cares about?
  • Defect (c), which is about const and intent rather than safety: what does returning a mutable reference to the course let a caller do to a registry-managed enrolment?
  • A redesign, at most one paragraph, that removes both: where the owned objects live, what the non-owning members are, and what the return type of enrol becomes.
  • How you would have caught it before shipping. A test, a tool, or a rule — one of the three, with a concrete example. "Review more carefully" is not an answer.

Would make it weak. Naming the categories without a scenario; a redesign that fixes the leak by deleting the destructor; or missing the interaction between ~Enrolment and vector reallocation, which is the interesting part.


X2 — design the ownership for a system with three lifetimes [L5 Design]

The problem. A timetabling system has four kinds of object with different lifetimes: rooms (exist for years), lecturers (exist while employed), course offerings (one per term), and sessions (one per meeting of an offering). Sessions refer to a room and a lecturer, and to their offering.

Design it. Deliver: (a) the ownership diagram with multiplicities and lifetimes; (b) the class declarations, with every member's form (value / pointer / reference / container) justified in a comment; (c) the answer to "what happens when a lecturer leaves in week 6, with sessions scheduled?" — as a policy, not a crash; (d) the answer to "what happens when a room is closed?" — and an explanation of why it is or is not the same answer; (e) one operation that a caller genuinely needs, implemented without exposing a container.

Success looks like. Four lifetimes answered explicitly; no borrowed member without a lifetime sentence; the two "what happens when" questions answered differently, with the asymmetry explained (a lecturer is attached to sessions by identity, a room by availability — or your own distinction, argued). Requirement: (c) must describe a state the program can be in, not a state that cannot occur.

Would make it weak. Storing Room* and Lecturer& without saying why the two forms differ; making every relationship an owning one "for safety"; or a policy answer that amounts to "assert it never happens".


X3 — evaluate "composition over inheritance" [L8 Evaluate]

The problem. GoF's sentence, evaluated with this repository's own code as evidence.

What a good answer contains.

  • Two worked cases from the course: FixedStack against BrokenStack (Module 6) and DeadlineQueue against class DeadlineQueue : public std::deque<Submission> (Module 9). For each, name the specific defect, the specific line that fixed it, and what the fix cost (forwarders, and how many).
  • One case where inheritance stays: from this course, or from the standard library. Say what makes it right — the is-a test, the completeness of the base's operations, and the base having been written to be derived from. Argue it rather than conceding it.
  • The cost of composition, named honestly: forwarding, and interface duplication when two classes wrap the same thing differently.
  • The arguably-defensible middle: a small class with two subclasses you control, a stable hierarchy and a designed base. Say what evidence would make you keep it, and what would make you flatten it.
  • Review criteria, two rules phrased so they can be applied to a diff.

How you will be judged. Whether a reader who disagrees can follow the reasoning, whether both worked cases cite the actual code, and whether the review criteria are checkable rather than aesthetic.


The rubric

Applied to X1, X2 and X3 alike. Score each row 2 (done), 1 (present but weaker), 0 (absent).

Criterion
1 The problem is restated as a scenario in one sentence before any fix appears
2 Every claim is checkable — a program, a measurement, a named source
3 Every borrowed relationship has a written lifetime requirement
4 The alternative is described fairly enough that its advocate would recognise it
5 The condition that would reverse the decision is named
6 The answer ends with something a reader can apply: a test, a rule, or a file to change

X1 has right answers, so rows 1–3 carry the marks. X2 and X3 have no single right answer, so rows 4 and 5 do.


Evaluating your own answer

Write these three lines before reading any suggested approach:

My decision:
The trade-off I accepted:
What I would do differently with more time:

Then compare against the "what a good answer contains" list, item by item, and mark each one present, missing, or present but weaker than the list. The third category is where the marks are: an answer that says "the vector can reallocate" but cannot name the line that creates the dangling reference has the vocabulary and not the model.

Two questions to close with:

  1. Could a reader who disagreed with you still follow your reasoning? If your answer only works for someone who already agrees, it is a preference, not an argument.
  2. What would make you change your mind? A concrete observation — a reallocation you measured, a caller that needed the container after all, a defect a reviewer found — not "more experience".

Next: Self-assessment — ten questions, including three predictions and a design to correct. · All modules