Search code examples
c++observer-patternshared-ptr

Check if container of shared_ptr contains a pointer?


Using Observer pattern. I have a class, called Monitor for example, that is monitoring a collection of objects. The class is an Observer and each object in it's collection is a Subject. Currently the collection is implemented as a std::list of shared_ptr. In the Update method of the Monitor class I want to check if the update is coming from one of the objects in it's collection.

std::list<SomeSharedPointer> items_;
...
void Monitor::Update(Subject *subject)
{
    if(subject == something_)
    {
        DoSomething();
    }
    else if
    ??
    // if subject is one of the objects in our collection then do something..

}

Subject here is a raw pointer and my collection is a list of shared_ptr. How can I effectively check if the subject coming in is any one of the objects in my collection?

(Note my compiler, msvc, supports lambdas if there is an algorithmic solution requiring one)

UPDATE

I should add that I realize I can use a for loop over the container, but I'm wondering if there's a snazzier way.

UPDATE 2

SomeSharedPointer is a typedef for std::shared_ptr<SomeType> where SomeType derives from abstract class Subject (standard Observer pattern implementation). SomeType will at some point call Notify() which will call the Update() method for each observer.


Solution

  • auto i = std::find_if(items_.begin(), items_.end(), 
        [=](const SomeSharedPointer& x) { return x.get() == subject; });
    
    if (i != c.end())
    { 
        // Object found, and i is an iterator pointing to it
    }
    

    A little helper method can make this more readable:

    typedef std::list<SomeSharedPtr> ObserverCollection;
    
    // You can also add a const version if needed
    ObserverCollection::iterator find_observer(Subject* s)
    {
        return std::find_if(items_.begin(), items_.end(), 
            [=](const SomeSharedPointer& x) { return x.get() == s; });
    }
    

    Then, you use it like this if you need the iterator

    auto i = find_observer(subject);
    if (i != items_.end())
    {
        // Object found
    }
    

    or simply like this if you don't:

    if (find_observer(subject) != items_.end())
    {
        ...
    }