Skip to content

Practice Lab 17 — Library lending ownership model

Difficulty: Intermediate · Estimated time: 5 hours · Module 9: Composition, Aggregation and Association

Every object in this lab has a lifetime relationship with another object. Your job is to name it, draw it, and prove it with counters.


At a glance

Difficulty Intermediate
Estimated time 5 hours
Module Module 9 — Composition, Aggregation and Association
Concepts practised Has-a relationships, composition, aggregation, association, ownership, object lifetime, nested objects, dependency direction
Prerequisite Practice Lab 16
Class design yours — the relationships are the deliverable

Scenario

A branch library lends items to members, records loans, and takes reservations. Its data has four relationships that look similar and are not:

  • a library and its items — the items belong to it;
  • a loan and the item it concerns — the item exists whether or not it is on loan;
  • a member and their loans — the loan exists because the member borrowed;
  • a reservation and the member who made it — the reservation refers to the member, who may leave.

Getting these four the same way produces code that either leaks, or destroys something still in use, or (happily) compiles and misbehaves in a way nobody notices for a month.


Problem statement

Design and implement the branch's model. The classes are yours; the relationships are the requirement.

  1. Items (with at least two kinds), members, loans and reservations.
  2. Lending rules: a member has a limit, an item can be lent once, and a reservation is honoured when an item is returned.
  3. A record of every loan that has ever happened, which survives the return of the item.
  4. At least one relationship of each kind: composition, aggregation, association, and a plain dependency in a function parameter.
  5. Lifetime narration in every class, so that every creation and destruction is visible in the output.

Deliverables in ownership.md:

  • A diagram of the classes with the four relationship kinds marked, and the multiplicities.
  • For every arrow: the has-a sentence, the ownership rule, and the line of code that expresses it (a member by value, a reference, or a value in a container).
  • A lifetime trace: for one scripted sequence, the exact order of creations and destructions you predicted, and the actual order.

Learning objectives

By the end of this lab you will be able to:

  • Choose composition, aggregation or association for a relationship, and justify it from lifetimes rather than from convenience.
  • Express ownership in code: a member by value for composition, a reference for association.
  • Predict and then verify the construction and destruction order of nested objects.
  • Find the relationship that a design got wrong by looking at what outlives what.
  • Name the multiplicity of a relationship, and say what changes when it changes.

Functional requirements

  1. At least two kinds of item, sharing what is genuinely shared.
  2. A member has a borrowing limit that is enforced, with a refusal naming the limit and the current count.
  3. An item on loan cannot be lent again; the refusal names the borrower.
  4. Returning an item honours the earliest outstanding reservation for that item, and the reservation is removed once honoured.
  5. A loan records when it was made and when it was returned, and remains in the history afterwards.
  6. The history lists every loan ever made, including returned ones, in a documented order.
  7. No operation copies an item or a member into a loan: a loan refers to them. Prove it by narrating every copy in a copy constructor and showing the copy count stays zero during lending.
  8. Nothing is destroyed while still referred to: the history is destroyed after the loans, and the narration order proves it.
  9. A const library can print its items and its history.
  10. At least one of your classes takes a collaborator it does not own — a reference or a pointer whose owner is documented in a comment at the member.

Constraints

  • Header and source files per class, with a documented build command.
  • No smart pointers in this lab — it is about choosing the relationship, and a smart pointer would make some of those choices for you. Module 11 will convert this model, and you may revisit the notes then.
  • No templates.
  • Every class narrates construction and destruction, with the class name and an identifier.
  • No warnings.

Starter task

In ownership.md, before coding:

  1. Draw the four relationships and name each one's kind, with the multiplicity.
  2. Write the member declaration that expresses each: by value, by reference, in a container, or in a function parameter only.
  3. For the four objects in a scripted sequence — create the library, add two items, add a member, lend an item, return it — predict the destruction order exactly.
  4. Write the one relationship you expect to be hardest, and why.

Implementation tasks

  1. Implement the item hierarchy and the member, with narration.
  2. Implement the loan history, then lending, returning and reservation handling.
  3. Write the scripted sequence from the starter task and record the narration.
  4. Compare with the prediction and explain every difference.
  5. Break one relationship deliberately: change an owning member to a reference that outlives its owner is not possible in your own code without a dangling reference — so instead, record what would happen if the library were destroyed before the loans, and what stops it in your design.
  6. Write ownership.md with the diagram, the sentences and the trace.

Test cases

# Action Expected result
1 Lend an item to a member Loan created; the item is on loan; one narration pair for the loan
2 Lend the same item again Refused, naming the borrower
3 Lend to a member at their limit Refused, naming limit and count
4 Return an item with a reservation waiting The reservation is honoured and removed
5 Print the history after a return The loan is still listed, with both dates
6 Copy count during lending 0 — no item or member was copied
7 Destruction order for the scripted sequence Exactly the prediction, or the difference explained
8 Print a const library Compiles and prints the same output
9 Return an item that is not on loan Refused
10 Reserve an item that is on the shelf Refused, or accepted and immediately honoured — your documented rule
11 Reserve the same item twice by the same member Refused
12 Destroy the library and the members Every narration appears exactly once; nothing is destroyed twice

Boundary cases to run deliberately: a library with no items; a member with no loans; an item reserved by two members and returned once; a limit of 1.


Expected behaviour

[catalogue ctor] branch A
[item ctor] B-1 Compilers
[item ctor] B-2 Algorithms
[member ctor] M-1 Ayesha Khan
[loan ctor] B-1 -> M-1
[item ctor-copy] (never printed during lending: the loan refers, it does not copy)
lend B-1 again -> refused: on loan to M-1
return B-1 -> honoured the reservation of M-2
history: 1 loan, B-1 -> M-1, out 20260414, back 20260415
[catalogue dtor] branch A
[item dtor] B-2 Algorithms
[item dtor] B-1 Compilers
[member dtor] M-1 Ayesha Khan

Extension challenge

Add inter-library loans: an item owned by one branch is lent to a member of another.

Record in ownership.md:

  • What the relationship between the two branches now is, and what it is not.
  • Which class owns the item, and how the other branch refers to it without owning it.
  • What happens when one branch is destroyed while an inter-library loan is outstanding — and the rule you chose for it, in one sentence.
  • The change cost: files, operations, lines.

Debugging challenge

Members are destroyed before their loans, and the program prints nonsense afterwards:

class Library {
public:
    Loan& make_loan(const Member& member, const Item& item) {
        Loan loan(member, item);          // a local loan
        history_.push_back(loan);         // copied into the history
        return history_.back();           // a reference into a container that may grow
    }
private:
    std::vector<Loan> history_;
};

Reproduce it — make two loans and use the first reference after the second — and answer:

  1. What is dangling, and what caused it: the local, the copy, or the reallocation?
  2. Which relationship in the model is this code trying to express, and which one did it accidentally create?
  3. Write the version that keeps the reference valid, and say what it costs.
  4. Which test case in the table catches it?

Reflection questions

  1. Which of the four relationships was hardest, and what made it hard: the lifetime, the multiplicity, or the ownership?
  2. A loan refers to a member and an item. What happens if the member leaves? Answer with what your design does, and what it should do.
  3. Your history grows. What does that mean for references into it, and how did you handle it?
  4. Which of your members is a reference rather than a value, and who guarantees its lifetime? Write that guarantee where a reader would find it.
  5. The reservation is removed when honoured. What if the member has left the library by then?
  6. If a library had to own its loans but members could move between branches, which relationships would change, and how many? Answer with a number.

Completion checklist

  • [ ] It builds from a documented command with -Wall -Wextra -Werror and no warnings
  • [ ] ownership.md has a diagram with relationship kinds and multiplicities
  • [ ] Every relationship has a has-a sentence and the line of code that expresses it
  • [ ] At least one relationship of each kind exists, including a plain dependency
  • [ ] The lifetime trace was predicted before running, and every difference is explained
  • [ ] Lending copies neither an item nor a member — the copy narration count proves it
  • [ ] Reservations are honoured in order, and refused for duplicates
  • [ ] Destructor narrations appear exactly once each
  • [ ] All twelve test cases run, with output recorded
  • [ ] The debugging challenge was explained before being fixed
  • [ ] I can point at each member and say who owns it, without reading the diagram

Related: Lab index · Module 9 — Composition and Association · Previous: Practice Lab 16 · Next: Practice Lab 18 — University course registration