Using weak_ptr.lock() to remove observers when dead

Viewed 417

I am currently trying to implement the Observer pattern in a little game, using this as reference. Though, I am trying to implement a solution to one of the problems exposed in the chapter : how to prevent the subject from sending a notification to a removed observer ?

Instead of having simple pointers or owning the observers in the subject class (with a vector of shared_ptrs, simple pointers, or anything that implies owning the object), I thought that it could be good to have weak_ptrs (knowing that the observers are already instantiated using make_shared and shared_ptr). The primary use of this to me would be to be able to check if the observer is still alive with weak_ptr.lock() and to remove it if it isn't, but is this a good practice ? Does this implies other problems ?

Here's my (stripped down) code :

Main method :

int main() {
    shared_ptr<Game> game = std::make_shared<Game>(); //Game extends subject
    shared_ptr<Renderer> renderer = std::make_shared<Renderer>(); //Renderer extends observer
    game.addObserver(renderer); //Automatic cast from shared_ptr to weak_ptr
}

Subject class :

class Subject {
public:
    virtual void removeObserverAt(int index) {
        m_observers.erase(m_observers.begin() + index);
    }
protected:
    virtual void notify(int objectID, Event ev, int64_t timestamp) {
        int i = 0;
        for(std::weak_ptr<Observer> obs : m_observers) {
            if(auto sobs = obs.lock()) {
                sobs->onNotify(objectID, shared_from_this(), ev, timestamp);
            } else {
                removeObserverAt(i);
            }
            i++;
        }
    }
private:
    std::vector<std::weak_ptr<Observer>> m_observers;
};

Observer class :

class Observer {
public:
    virtual ~Observer() {}
    virtual void onNotify(int objectID, std::weak_ptr<Subject> caller, Event ev) = 0;
private:
};
0 Answers
Related