Step 3 of 7
Observers with weak_ptr
In the Observer pattern, a subject (a stock ticker, a button, a scoreboard) notifies a list of listeners when something happens. The hard part in C++ is lifetime: if a listener is destroyed while the subject still holds a raw pointer to it, the next notification uses a dangling pointer and the program crashes, or worse.
Storing std::weak_ptr solves it. The subject doesn't keep listeners alive, and lock() tells it whether each one still exists.
#include <iostream>
#include <memory>
#include <string>
#include <vector>
struct Screen {
std::string name;
void show(double price) const { std::cout << name << " shows " << price << "\n"; }
};
class Ticker {
public:
void attach(const std::shared_ptr<Screen>& s) { screens_.push_back(s); }
void update(double price) {
for (const auto& w : screens_) {
if (auto s = w.lock()) s->show(price); // alive: notify
}
}
std::size_t attached() const { return screens_.size(); }
private:
std::vector<std::weak_ptr<Screen>> screens_;
};
int main() {
Ticker t;
auto lobby = std::make_shared<Screen>(Screen{"lobby"});
t.attach(lobby);
{
auto phone = std::make_shared<Screen>(Screen{"phone"});
t.attach(phone);
t.update(101.5);
} // phone is destroyed here
t.update(99.0); // skipped safely: lock() returns empty
std::cout << t.attached() << " entries still stored\n";
}
lobby shows 101.5
phone shows 101.5
lobby shows 99
2 entries still stored
How it works
- The owners (
mainhere) holdshared_ptrs. The ticker only holdsweak_ptrs, so it never keeps a screen alive. lock()returns ashared_ptrthat keeps the object alive during the call, or an empty one if it's already gone.
The leftover entry
Notice the ticker still stores 2 entries after phone died. The dead weak_ptr is harmless, but over time a long-running subject would collect thousands of them. Your task fixes this: remove expired entries while publishing. std::erase_if(listeners_, [](const auto& w) { return w.expired(); }) does it in one call, or you can build a new vector of the live ones as you notify.
Your turn: implement Scoreboard::subscribe and Scoreboard::publish. publish notifies every living listener in subscription order, removes expired ones, and returns how many were notified.