Note that there are some explanatory texts on larger screens.

plurals
  1. POObserver pattern using weak_ptr
    text
    copied!<p>I'm trying to write a safe <code>Subject</code> class from the <a href="http://en.wikipedia.org/wiki/Observer_pattern" rel="nofollow noreferrer">observer pattern</a>. I want to know if using <code>weak_ptr</code> is the best way to store <code>IObserver</code> instances in such a way that:</p> <ul> <li>It is not possible to use an <code>IObserver</code> instance after it has been free'd.</li> <li>The <code>Subject</code> class does not hold on to <code>IObserver</code> references that should be free'd (<a href="http://en.wikipedia.org/wiki/Lapsed_listener_problem" rel="nofollow noreferrer">lapsed listener problem</a>).</li> <li>The <code>Subject</code> class must be thread safe.</li> </ul> <p>Unfortunately, our coding standards say that we're not allowed to use boost. I guess I was a bad person in a previous life. Fortunately, I am allowed to use C++11 (what is shipped with Visual Studio 2012).</p> <p>Here is a sample <code>Observer</code> class.</p> <pre class="lang-cpp prettyprint-override"><code>// Observer interface that supports notify() method class IObserver { public: virtual void notify() const = 0; virtual ~IObserver() {} }; // Concrete observer implementation that prints a message class Observer : public IObserver { public: Observer( const std::string&amp; message) : m_message( message ){} void notify() const { printf( "%s\r\n", m_message.c_str() ); } private: std::string m_message; }; </code></pre> <p>And here is the <code>Subject</code> class. </p> <pre class="lang-cpp prettyprint-override"><code>// Subject which registers observers and notifies them as needed. class Subject { public: // Use shared_ptr to guarantee the observer is valid right now void registerObserver( const std::shared_ptr&lt;IObserver&gt;&amp; o ) { std::lock_guard&lt;std::mutex&gt; guard( m_observersMutex ); m_observers.push_back( o ); } void unregisterObserver( const std::shared_ptr&lt;IObserver&gt;&amp; o ) { std::lock_guard&lt;std::mutex&gt; guard( m_observersMutex ); // Code to remove the observer from m_observersMutex } // This is a method that is run in its own thread that notifies observers of some event void doNotify() { std::lock_guard&lt;std::mutex&gt; guard( m_observersMutex ); // Notify any valid observers of events. std::for_each( m_observers.cbegin(), m_observers.cend(), []( const std::weak_ptr&lt;IObserver&gt;&amp; o ) { auto observer = o.lock(); if ( observer ) { observer-&gt;notify(); } } ); // Remove any dead observers. These are ones which have expired(). m_observers.erase( std::remove_if( m_observers.begin(), m_observers.end(), []( const std::weak_ptr&lt;IObserver&gt;&amp; o ) { return o.expired(); } ), m_observers.end() ); } private: std::vector&lt;std::weak_ptr&lt;IObserver&gt;&gt; m_observers; std::mutex m_observersMutex; }; </code></pre> <p>Here's some code that exercises <code>Subject</code>:</p> <pre class="lang-cpp prettyprint-override"><code>int main(int argc, wchar_t* argv[]) { Subject subject; auto observerHello = std::make_shared&lt;Observer&gt;( "Hello world" ); subject.registerObserver( observerHello ); { // Create a scope to show unregistration. auto observerBye = std::make_shared&lt;Observer&gt;( "Good bye" ); subject.registerObserver( observerBye ); subject.doNotify(); } printf( "%s\r\n", "Observer good bye is now be destructed" ); subject.doNotify(); return 0; } </code></pre> <p>Is my usage of <code>weak_ptr</code> thread-safe? From here <a href="https://stackoverflow.com/a/2160422/1517648">https://stackoverflow.com/a/2160422/1517648</a> I <em>think</em> it is.</p> <p>Is this a legitimate way of solving the lapsed listener problem?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload