Mini Project 4 — Visitor Counter¶
Difficulty: Beginner · Estimated effort: 2 hours · Prerequisites: Module 5 — Operators and Static Members · Combines: static members, class-level state, the Rule of Zero
No complete solution is provided. This is a short project, so the checklist is short too — which is not the same as easy.
1. Scenario¶
A small museum has a single turnstile and no budget for a system. The staff want a program that models the gallery: how many people are inside right now, how many have entered since it opened, and the maximum that were inside at any one time. When the building closes with anyone still inside, that is an incident worth recording.
2. Problem statement¶
Build a VisitorCounter type that tracks the number currently inside and the running totals,
plus a Visitor type whose construction and destruction drive it — so that "someone entered"
and "someone left" are properties of a visitor's lifetime rather than calls a programmer
remembers to make.
3. User requirements¶
- [ ] See how many are inside right now.
- [ ] See the total entries for the day and the peak occupancy.
- [ ] Have entry and exit recorded automatically when a visitor arrives or leaves.
- [ ] Get a warning at closing time if anyone is still inside.
- [ ] Have the counters reset for a new day without restarting the program.
4. Functional requirements¶
- [ ]
VisitorCounter::inside(),total(),peak()— read-only queries. - [ ] A
Visitorobject whose construction increments and whose destruction decrements. - [ ] Peak occupancy updated on every entry.
- [ ] A
reset()that clears the day's numbers and reports how many were still inside. - [ ] Automatic cleanup demonstrated on a path that leaves early (an early
return).
5. Non-functional requirements¶
- [ ] The shared state is
staticand private, with no public counters to poke at. - [ ]
Visitoris not copyable — a copy would double-count, and the compiler should refuse. - [ ] No manual
enter()/exit()calls anywhere inmain; lifetimes do the work. - [ ] Builds warning-free with
g++ -std=c++17 -Wall -Wextra -Werror. - [ ] The type follows the Rule of Zero or states why it does not.
6. Suggested features¶
- A per-hour count, using a small array indexed by hour, printed as a simple histogram.
- A
Wardtype that owns a group of visitors and reports its own occupancy. - Move semantics for
Visitor, with the counting rules for moved-from objects written down.
7. OOP concepts involved¶
| Concept | Where it appears |
|---|---|
| Static members | The counters are class-level, shared by every visitor |
| Constructors / destructors | Entry and exit are the object's lifetime, not a remembered call |
| RAII as a counting device | Correct counting follows from correct lifetimes |
| Deleted functions | Visitor(const Visitor&) = delete prevents the double-count bug |
| Encapsulation | Nothing outside can set a counter to a wrong value |
8. Suggested design considerations¶
Ask what should happen when a Visitor is copied. The intuitive answer, "count it twice",
is wrong: a copy is a second name for the same visit, not a second visit. Deleting the copy
constructor turns a run-time miscount into a compile error, which is the better bug.
Separate the counter from the visitor. VisitorCounter holds the shared state; Visitor
holds nothing but its own identity. If a visitor starts holding a copy of the totals, the
totals can disagree.
Decide where the peak is computed. Recomputing it at query time is simpler; tracking it on entry is cheaper and easier to test. Either is fine if it is chosen on purpose.
9. Minimum viable version¶
VisitorCounter with the three queries, a reset(), and Visitor with a deleted copy
constructor. A main that creates visitors in a loop, destroys some early, and prints the
totals.
10. Intermediate extension¶
Add a scope in main containing visitors that are destroyed early, and demonstrate that the
"inside" count returns to the correct value when the scope ends — including when the scope is
left through an early return. Then remove the deleted copy constructor deliberately and
observe whether your tests would have caught the double-count.
11. Advanced extension¶
Add move semantics and write down the rule for a moved-from visitor: does it still hold a place in the room? Implement whichever answer you choose, then test the sequence move → destroy → destroy, and check that the count matches your documented rule rather than your intuition.
12. Testing checklist¶
- [ ] Constructing n visitors reports n inside and n total
- [ ] Destroying one reports n − 1 inside and n total
- [ ] Peak is the highest inside value ever seen, not the final one
- [ ] An early
returnfrom a scope still decrements - [ ]
reset()reports the number left inside and zeroes the day - [ ] Attempting to copy a
Visitorfails to compile, and you have the diagnostic recorded - [ ] A second day's counts do not include the first day's numbers
13. Documentation checklist¶
- [ ] A header comment explaining that counting is driven by lifetimes
- [ ] Why copying is deleted, in one sentence
- [ ] The reset semantics: what is cleared, what is reported
- [ ] The move rule, if you implemented move semantics
- [ ] A note saying the counters are not thread-safe
14. Self-evaluation rubric¶
| Criterion | Excellent looks like | Weight |
|---|---|---|
| Correct accounting | Counts are right on the normal and the early-return path | 30% |
| Design | Shared state in one class; visitors hold no totals | 25% |
| Compile-time safety | Copying is impossible, not merely discouraged | 20% |
| Interface | Queries are const; nothing exposes a settable counter |
15% |
| Documentation | Moved-from and copy rules written down | 10% |
Related: Mini projects · Project roadmap · All projects · Module 5 — Operators and Static Members