Memento
Learning Objectives
Capture and restore an object's state without breaking encapsulation.
Implement undo with snapshots; understand memory and serialization caveats.
Prerequisites: Modules 12, 42.
Intuition and Definition
Intent: without violating encapsulation, capture and externalize an object's internal state so the object can be restored to it later.
Participants: Originator (creates mementos of its own state and restores from them), Memento (opaque snapshot), Caretaker (stores mementos, never inspects them).
Why It Matters
Undo, checkpoints, "cancel" buttons in settings dialogs and transaction rollback all need to restore a previous state exactly — without exposing private fields to the code that stores the snapshots.
Syntax and Language Notes
In C++ the memento's state can be private with the originator as a friend, or the memento can be an opaque nested type. In GC languages, immutable state objects make snapshots cheap (share unchanged parts).
Complete Example
#include <iostream>
#include <string>
#include <vector>
class DisplaySettings { // Originator
int brightness_ = 70;
std::string theme_ = "day";
std::vector<std::string> gauges_{"speed", "rpm"};
public:
class Snapshot { // Memento: opaque to everyone else
friend class DisplaySettings;
int brightness_; std::string theme_; std::vector<std::string> gauges_;
Snapshot(int b, std::string t, std::vector<std::string> g) : brightness_(b), theme_(std::move(t)), gauges_(std::move(g)) {}
};
Snapshot save() const { return Snapshot(brightness_, theme_, gauges_); }
void restore(const Snapshot& s) { brightness_ = s.brightness_; theme_ = s.theme_; gauges_ = s.gauges_; }
void setBrightness(int b) { brightness_ = b; }
void setTheme(std::string t) { theme_ = std::move(t); }
void addGauge(std::string g) { gauges_.push_back(std::move(g)); }
std::string describe() const {
std::string s = "brightness " + std::to_string(brightness_) + ", theme " + theme_ + ", gauges:";
for (const auto& g : gauges_) s += " " + g;
return s;
}
};
int main() {
…current: brightness 5, theme night, gauges: speed rpm coolant
cancel changes: brightness 30, theme night, gauges: speed rpm
factory reset: brightness 70, theme day, gauges: speed rpmStep-by-Step Walkthrough
save() copies the private state into a Snapshot whose members only DisplaySettings can read.
The caretaker (history) keeps snapshots but cannot inspect or modify them.
restore() puts the exact previous state back — including the gauge list.
Common Mistakes
Huge snapshots taken too often (memory blow-up) — snapshot diffs, cap history, or use persistent data structures.
Shallow snapshots that share mutable data with the live object.
Using mementos as a serialization format — internal layout changes break old saved files; version them if persisted.
Leaking state by making memento fields public.
Trade-offs and Alternatives
Memento (store state) vs Command undo (store inverse operations): mementos are simple and exact but cost memory; commands are compact but need correct inverses. Event sourcing stores events and rebuilds state by replay.
Real-World Use
Undo in editors, game save points, settings dialogs with Cancel, database savepoints, browser history state, configuration rollback in ECU calibration tools.
Practice
Q1. (Easy) Which participant creates mementos?
Answer: The originator.
Q2. (Medium) Why can't the caretaker read the memento's fields?
Answer: To preserve the originator's encapsulation — only it should know and interpret its internal state.
Q3. (Advanced) How would you limit the memory used by an undo history of mementos?
Answer: Keep a bounded deque (drop the oldest), snapshot only changed parts (diffs), or use structurally shared immutable state so unchanged parts aren't duplicated.
Interview Question
Q1. "Memento or Command for undo?" Answer: Command stores *operations* and their inverses — compact and good for fine-grained edits, but every operation needs a correct undo, and undo can drift if state changed outside commands. Memento stores *state snapshots* — trivially correct restore, works for operations with no simple inverse, but costs memory proportional to state size and frequency. Many editors combine them: commands for normal edits, mementos for complex operations.
Quick Quiz
Q1. What does the caretaker do?
Answer: Stores mementos and hands them back; never inspects them.
Q2. Main cost of Memento?
Answer: Memory for snapshots.
Q3. How does C++ let only the originator read the memento?
Answer: Private members with the originator as friend (or an opaque nested type).
Summary
Memento snapshots and restores state without exposing internals.
Watch memory, depth of copies and persistence versioning.
Related: Modules 12, 42.