Here is a simplified observer pattern:
- one creator creates a profile when it starts and "destroy" it when it is done.
- zero, one or more observers try to "look at" the profile at any time.
To implement it, the trick is that observers shall refcnt profile, so the last observer (or creator) can safely destroy it.
I can do it without shared_ptr/weak_ptr, but I wonder if using them can avoid re-inventing wheels.
Here is my code:
#include <iostream>
#include <memory>
#include <thread>
#include <cassert>
volatile bool playing = true;
class Profile {
public:
int a_;
Profile(int v) {a_ = v;}
};
std::shared_ptr<Profile> g_profile{ nullptr };
void observer() {
do {
// observe profile if I can
std::weak_ptr<Profile> weak = g_profile;
if (auto prof = weak.lock()) {
auto a = prof->a_;
// if prof is stable, I shall see the same a_
assert(a == prof->a_);
}
else {
std::cout << ".";
}
} while (playing);
}
void creator() {
do {
// create profile when I start
g_profile.reset(new Profile(std::rand()));
std::weak_ptr<Profile> weak = g_profile;
assert(weak.lock() != nullptr);
// doing some work ...
// destroy profile when I am done
g_profile.reset();
} while (playing);
}
void timer() {
std::this_thread::sleep_for(std::chrono::seconds(10));
playing = false;
}
int main() {
std::thread cr{ creator };
std::thread ob{ observer };
std::thread tm{ timer };
cr.join();ob.join();tm.join();
// no memory leak
}
But the program crashes either at
std::weak_ptr<Profile> weak = g_profile
or assert(a == prof->a_)
. So here are my questions:
- do you have a pointer implementing observer pattern (or variant) with shared_ptr/weak_ptr?
- what's wrong with the above code? Can you make it right?