I've run into a problem where a weak_ptr<> is segfaulting when I try
to do a lock() call on it. It doesn't happen all the time, and I'm at
a loss to see what's causing the problem.
I have an implementation of the Observer pattern in my code using
shared_ptr/weak_ptr:
class Observer {
public:
virtual void update(shared_ptr<Observed> d) = 0;
...
}
class Observed : public enable_shared_from_this<Observed> {
vector _observers;
public:
void register(shared_ptr<Observer> o)
{
_observers.push_back(weak_ptr<Observer>(o));
}
void notifyObservers()
{
vector::iterator i;
for (i = _observers.begin(); i != _observers.end(); observer++)
{
shared_ptr<Observer> o = i->lock();
if (o) o->update(shared_from_this());
}
}
...
}
I'm trying to write a wxWidget that participates in the above Observer
scheme, but quickly ran into a problem: wxWidgets passes around raw
pointers and handles its own garbage-collection. If I created a
shared_ptr<MyWidget>, wx would feel perfectly free to delete the
object out from under the shared_ptr<>, which would be bad.
My solution was:
template <typename T>
class wxObserver : public Observer {
private:
T* p;
wxObserver();
public:
wxObserver(T* p) : p(p);
void update(shared_ptr<Observed> o) { if (p) p->update(o); }
}
class MyWidget : public wxWidget {
private:
shared_ptr observer;
public:
MyWidget(...) : wxWidget(...), observer(this) { ...
observed->register(observer); ... }
...
}
The idea is that when a MyWidget is created, it creates a shared
pointer to a wxObserver and can register that wxObserver with observed
objects without a problem. When wxWidgets chooses to delete the
MyWidget, the shared pointer the MyWidget goes away, the wxObserver is
deleted, and the weak pointers held by the observed objects expire.
The implementation of Observed::notifyObservers() checks to make sure
that the observers still exist before update()ing them, and only the
live observers are updated.
The problem is that sometimes, after wxWidgets destroys a MyWidget,
calls to Observed::notifyObservers() crashes with a segfault within
the call to i->lock().
I can't see what's causing this. Worse, while it crashes consistantly
and repeatedly at the same line, it doesn't appear to always crash
after the same amount of work. Putting various {cerr << "got
here";}-type lines within the code above doesn't always yield exactly
the same results from run to run, even without recompiling. My
thoughts are now that it might be a threading issue.
Is there any good solutions to this problem?
thanks,
Buddha