Search code examples
c++pointersshared-ptrobserver-pattern

c++ Observer Pattern: raw pointers vs shared_ptr?


I'm in the process of converting (at least) some of my code to using shared_ptr. However I'm running into an issue with the Observer pattern which I'm using.

I have a presenter class (Model View Presenter) which implements the Observer pattern and it gets notified when certain events happens. I wrote generic Subject/Observer classes that any class can inherit from. The update method looks something like this:

void MyPresenter::Update(Subject *subject)
{
    if(subject == myService_)
    {
        DoSomething();
    }
    else if(subject == myOtherService_)
    {
        DoSomethingElse();
    }

}

This worked fine until I converted myService_ (a member of MyPresenter class) to a std::shared_ptr. Now the expression (subject == myService_) is no longer valid.

I may eventually convert everything to shared_ptr, but until then is there an easy way for me to support both raw pointers and shared_ptr's with the Observer pattern? Ideally I'd like the observer pattern to be agnostic to the observer's pointer implementation but maybe that's not possible. How can I fix this?

UPDATE

Should an observer pattern Observer interface take a shared pointer? Or is it better to keep it as raw pointers? Currently I have:

class Subject;

class Observer
{
public:
    virtual ~Observer() {}
    virtual void Update(Subject *subject) = 0;

protected:
    Observer() {}
};

Solution

  • You can use shared_ptr's get member, which returns the raw pointer that the shared_ptr wraps:

    subject == myService_.get()
    

    In general I would not suggest to blindly convert all raw pointers to shared_ptrs. You always have to think about if the surrounding object really owns the pointed by object (and shared ownership is still ownership). Sometimes a std::unique_ptr (although I don't know if tr1 already has that, otherwise a std::auto_ptr) is a better choice, if it is strict ownership or also just a raw pointer, if it is no ownership.

    But in interfaces, especially function arguments and return values, raw pointers are often a better idea than using smart pointers and thus decreasing genericity (and also performance, though only insignificantly, but even more so for shared_ptr's).

    NOTE: I know this is the same answer as the already existing one, but I desperately felt the need against just suggesting to use shared_ptrs all over the place.