diff options
| -rw-r--r-- | indra/llcommon/llevents.h | 343 | ||||
| -rw-r--r-- | indra/llui/llnotifications.h | 34 | ||||
| -rw-r--r-- | indra/test/llevents_tut.cpp | 222 | 
3 files changed, 54 insertions, 545 deletions
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 253592256d..3c388bf176 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -310,37 +310,6 @@ testable:  };  /***************************************************************************** -*   details -*****************************************************************************/ -namespace LLEventDetail -{ -    /// Any callable capable of connecting an LLEventListener to an -    /// LLStandardSignal to produce an LLBoundListener can be mapped to this -    /// signature. -    typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc; - -    /// overload of visit_and_connect() when we have a string identifier available -    template <typename LISTENER> -    LLBoundListener visit_and_connect(const std::string& name, -                                      const LISTENER& listener, -                                      const ConnectFunc& connect_func); -    /** -     * Utility template function to use Visitor appropriately -     * -     * @param listener Callable to connect, typically a boost::bind() -     * expression. This will be visited by Visitor using boost::visit_each(). -     * @param connect_func Callable that will connect() @a listener to an -     * LLStandardSignal, returning LLBoundListener. -     */ -    template <typename LISTENER> -    LLBoundListener visit_and_connect(const LISTENER& listener, -                                      const ConnectFunc& connect_func) -    { -        return visit_and_connect("", listener, connect_func); -    } -} // namespace LLEventDetail - -/*****************************************************************************  *   LLEventTrackable  *****************************************************************************/  /** @@ -374,11 +343,6 @@ namespace LLEventDetail   *     instance, it attempts to dereference the <tt>Foo*</tt> pointer that was   *     <tt>delete</tt>d but not zeroed.)   *   - Undefined behavior results. - * If you suspect you may encounter any such scenario, you're better off - * managing the lifespan of your object with <tt>boost::shared_ptr</tt>. - * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression - * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging - * thread-safe Boost.Signals2 machinery.   */  typedef boost::signals2::trackable LLEventTrackable; @@ -517,44 +481,13 @@ public:       * the result be assigned to a LLTempBoundListener or the listener is        * manually disconnected when no longer needed since there will be no       * way to later find and disconnect this listener manually. -     * -     * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a -     * listener, listen() will inspect the components of that expression. If a -     * bound object matches any of several cases, the connection will -     * automatically be disconnected when that object is destroyed. -     * -     * * You bind a <tt>boost::weak_ptr</tt>. -     * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the -     *   referenced object would @em never be destroyed, since the @c -     *   shared_ptr stored in the LLEventPump would remain an outstanding -     *   reference. Use the weaken() function to convert your @c shared_ptr to -     *   @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr -     *   will produce a compile error (@c BOOST_STATIC_ASSERT failure). -     * * You bind a simple pointer or reference to an object derived from -     *   <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION) -     * * You bind a simple pointer or reference to an object derived from -     *   LLEventTrackable. Unlike the cases described above, though, this is -     *   vulnerable to a couple of cross-thread race conditions, as described -     *   in the LLEventTrackable documentation.       */ -    template <typename LISTENER> -    LLBoundListener listen(const std::string& name, const LISTENER& listener, +    LLBoundListener listen(const std::string& name, +                           const LLEventListener& listener,                             const NameList& after=NameList(),                             const NameList& before=NameList())      { -        // Examine listener, using our listen_impl() method to make the -        // actual connection. -        // This is why listen() is a template. Conversion from boost::bind() -        // to LLEventListener performs type erasure, so it's important to look -        // at the boost::bind object itself before that happens. -        return LLEventDetail::visit_and_connect(name, -                                                listener, -                                                boost::bind(&LLEventPump::listen_invoke, -                                                            this, -                                                            name, -                                                            _1, -                                                            after, -                                                            before)); +        return listen_impl(name, listener, after, before);      }      /// Get the LLBoundListener associated with the passed name (dummy @@ -598,13 +531,6 @@ private:  private: -    LLBoundListener listen_invoke(const std::string& name, const LLEventListener& listener, -        const NameList& after, -        const NameList& before) -    { -        return this->listen_impl(name, listener, after, before); -    } -      // must precede mName; see LLEventPump::LLEventPump()      LLHandle<LLEventPumps> mRegistry; @@ -814,261 +740,6 @@ private:  LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request,                               const std::string& replyKey="reply"); -/***************************************************************************** -*   Underpinnings -*****************************************************************************/ -/** - * We originally provided a suite of overloaded - * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call - * LLEventPump::listen(...) and then pass the returned LLBoundListener to - * LLEventTrackable::track(). This was workable but error-prone: the coder - * must remember to call listenTo() rather than the more straightforward - * listen() method. - * - * Now we publish only the single canonical listen() method, so there's a - * uniform mechanism. Having a single way to do this is good, in that there's - * no question in the coder's mind which of several alternatives to choose. - * - * To support automatic connection management, we use boost::visit_each - * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to - * inspect each argument of a boost::bind expression. (Although the visit_each - * mechanism was first introduced with the original Boost.Signals library, it - * was only later documented.) - * - * Cases: - * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass - *   the corresponding shared_ptr to slot_type::track(). Ideally that would be - *   the object whose method we want to call, but in fact we do the same for - *   any weak_ptr we might find among the bound arguments. If we're passing - *   our bound method a weak_ptr to some object, wouldn't the destruction of - *   that object invalidate the call? So we disconnect automatically when any - *   such object is destroyed. This is the mechanism preferred by boost:: - *   signals2. - * * One of the functions's arguments is a boost::shared_ptr<T>. This produces - *   a compile error: the bound copy of the shared_ptr stored in the - *   boost_bind object stored in the signal object would make the referenced - *   T object immortal. We provide a weaken() function. Pass - *   weaken(your_shared_ptr) instead. (We can inspect, but not modify, the - *   boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr - *   implicitly and just proceed.) - * * One of the function's arguments is a plain pointer/reference to an object - *   derived from boost::enable_shared_from_this. We assume that this object - *   is managed using boost::shared_ptr, so we implicitly extract a shared_ptr - *   and track that. (UNDER CONSTRUCTION) - * * One of the function's arguments is derived from LLEventTrackable. Pass - *   the LLBoundListener to its LLEventTrackable::track(). This is vulnerable - *   to a couple different race conditions, as described in LLEventTrackable - *   documentation. (NOTE: Now that LLEventTrackable is a typedef for - *   boost::signals2::trackable, the Signals2 library handles this itself, so - *   our visitor needs no special logic for this case.) - * * Any other argument type is irrelevant to automatic connection management. - */ - -namespace LLEventDetail -{ -    template <typename F> -    const F& unwrap(const F& f) { return f; } - -    template <typename F> -    const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); } - -    // Most of the following is lifted from the Boost.Signals use of -    // visit_each. -    template<bool Cond> struct truth {}; - -    /** -     * boost::visit_each() Visitor, used on a template argument <tt>const F& -     * f</tt> as follows (see visit_and_connect()): -     * @code -     * LLEventListener listener(f); -     * Visitor visitor(listener); // bind listener so it can track() shared_ptrs -     * using boost::visit_each;   // allow unqualified visit_each() call for ADL -     * visit_each(visitor, unwrap(f)); -     * @endcode -     */ -    class Visitor -    { -    public: -        /** -         * Visitor binds a reference to LLEventListener so we can track() any -         * shared_ptrs we find in the argument list. -         */ -        Visitor(LLEventListener& listener): -            mListener(listener) -        { -        } - -        /** -         * boost::visit_each() calls this method for each component of a -         * boost::bind() expression. -         */ -        template <typename T> -        void operator()(const T& t) const -        { -            decode(t, 0); -        } - -    private: -        // decode() decides between a reference wrapper and anything else -        // boost::ref() variant -        template<typename T> -        void decode(const boost::reference_wrapper<T>& t, int) const -        { -//          add_if_trackable(t.get_pointer()); -        } - -        // decode() anything else -        template<typename T> -        void decode(const T& t, long) const -        { -            typedef truth<(boost::is_pointer<T>::value)> is_a_pointer; -            maybe_get_pointer(t, is_a_pointer()); -        } - -        // maybe_get_pointer() decides between a pointer and a non-pointer -        // plain pointer variant -        template<typename T> -        void maybe_get_pointer(const T& t, truth<true>) const -        { -//          add_if_trackable(t); -        } - -        // shared_ptr variant -        template<typename T> -        void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const -        { -            // If we have a shared_ptr to this object, it doesn't matter -            // whether the object is derived from LLEventTrackable, so no -            // further analysis of T is needed. -//          mListener.track(t); - -            // Make this case illegal. Passing a bound shared_ptr to -            // slot_type::track() is useless, since the bound shared_ptr will -            // keep the object alive anyway! Force the coder to cast to weak_ptr. - -            // Trivial as it is, make the BOOST_STATIC_ASSERT() condition -            // dependent on template param so the macro is only evaluated if -            // this method is in fact instantiated, as described here: -            // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html - -            // ATTENTION: Don't bind a shared_ptr<anything> using -            // LLEventPump::listen(boost::bind()). Doing so captures a copy of -            // the shared_ptr, making the referenced object effectively -            // immortal. Use the weaken() function, e.g.: -            // somepump.listen(boost::bind(...weaken(my_shared_ptr)...)); -            // This lets us automatically disconnect when the referenced -            // object is destroyed. -            BOOST_STATIC_ASSERT(sizeof(T) == 0); -        } - -        // weak_ptr variant -        template<typename T> -        void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const -        { -            // If we have a weak_ptr to this object, it doesn't matter -            // whether the object is derived from LLEventTrackable, so no -            // further analysis of T is needed. -            mListener.track(t); -//          std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n"; -        } - -#if 0 -        // reference to anything derived from boost::enable_shared_from_this -        template <typename T> -        inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct, -                                      truth<false>) const -        { -            // Use the slot_type::track(shared_ptr) mechanism. Cast away -            // const-ness because (in our code base anyway) it's unusual -            // to find shared_ptr<const T>. -            boost::enable_shared_from_this<T>& -                t(const_cast<boost::enable_shared_from_this<T>&>(ct)); -            std::cout << "Capturing shared_from_this()" << std::endl; -            boost::shared_ptr<T> sp(t.shared_from_this()); -/*==========================================================================*| -            std::cout << "Capturing weak_ptr" << std::endl; -            boost::weak_ptr<T> wp(sp); -|*==========================================================================*/ -            std::cout << "Tracking shared__ptr" << std::endl; -            mListener.track(sp); -        } -#endif - -        // non-pointer variant -        template<typename T> -        void maybe_get_pointer(const T& t, truth<false>) const -        { -            // Take the address of this object, because the object itself may be -            // trackable -//          add_if_trackable(boost::addressof(t)); -        } - -/*==========================================================================*| -        // add_if_trackable() adds LLEventTrackable objects to mTrackables -        inline void add_if_trackable(const LLEventTrackable* t) const -        { -            if (t) -            { -            } -        } - -        // pointer to anything not an LLEventTrackable subclass -        inline void add_if_trackable(const void*) const -        { -        } - -        // pointer to free function -        // The following construct uses the preprocessor to generate -        // add_if_trackable() overloads accepting pointer-to-function taking -        // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type. -#define BOOST_PP_LOCAL_MACRO(n)                                     \ -        template <typename R                                        \ -                  BOOST_PP_COMMA_IF(n)                              \ -                  BOOST_PP_ENUM_PARAMS(n, typename T)>              \ -        inline void                                                 \ -        add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const   \ -        {                                                           \ -        } -#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY) -#include BOOST_PP_LOCAL_ITERATE() -#undef  BOOST_PP_LOCAL_MACRO -#undef  BOOST_PP_LOCAL_LIMITS -|*==========================================================================*/ - -        /// Bind a reference to the LLEventListener to call its track() method. -        LLEventListener& mListener; -    }; - -    /** -     * Utility template function to use Visitor appropriately -     * -     * @param raw_listener Callable to connect, typically a boost::bind() -     * expression. This will be visited by Visitor using boost::visit_each(). -     * @param connect_funct Callable that will connect() @a raw_listener to an -     * LLStandardSignal, returning LLBoundListener. -     */ -    template <typename LISTENER> -    LLBoundListener visit_and_connect(const std::string& name, -                                      const LISTENER& raw_listener, -                                      const ConnectFunc& connect_func) -    { -        // Capture the listener -        LLEventListener listener(raw_listener); -        // Define our Visitor, binding the listener so we can call -        // listener.track() if we discover any shared_ptr<Foo>. -        LLEventDetail::Visitor visitor(listener); -        // Allow unqualified visit_each() call for ADL -        using boost::visit_each; -        // Visit each component of a boost::bind() expression. Pass -        // 'raw_listener', our template argument, rather than 'listener' from -        // which type details have been erased. unwrap() comes from -        // Boost.Signals, in case we were passed a boost::ref(). -        visit_each(visitor, LLEventDetail::unwrap(raw_listener)); -        // Make the connection using passed function. -        return connect_func(listener); -    } -} // namespace LLEventDetail -  // Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to  // listen() fails in Boost code trying to instantiate LLEventListener (i.e.  // LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't @@ -1079,12 +750,4 @@ namespace boost      T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }  } -/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an -/// easy way to cast to the corresponding weak_ptr. -template <typename T> -boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr) -{ -    return boost::weak_ptr<T>(ptr); -} -  #endif /* ! defined(LL_LLEVENTS_H) */ diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 62cf41256b..cac687f53d 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -746,42 +746,24 @@ public:  	virtual ~LLNotificationChannelBase() {}  	// you can also connect to a Channel, so you can be notified of  	// changes to this channel -	template <typename LISTENER> -    LLBoundListener connectChanged(const LISTENER& slot) +    LLBoundListener connectChanged(const LLEventListener& slot)      { -        // Examine slot to see if it binds an LLEventTrackable subclass, or a -        // boost::shared_ptr to something, or a boost::weak_ptr to something.          // Call this->connectChangedImpl() to actually connect it. -        return LLEventDetail::visit_and_connect(slot, -                                  boost::bind(&LLNotificationChannelBase::connectChangedImpl, -                                              this, -                                              _1)); +        return connectChangedImpl(slot);      } -	template <typename LISTENER> -    LLBoundListener connectAtFrontChanged(const LISTENER& slot) +    LLBoundListener connectAtFrontChanged(const LLEventListener& slot)      { -        return LLEventDetail::visit_and_connect(slot, -                                  boost::bind(&LLNotificationChannelBase::connectAtFrontChangedImpl, -                                              this, -                                              _1)); +        return connectAtFrontChangedImpl(slot);      } -    template <typename LISTENER> -	LLBoundListener connectPassedFilter(const LISTENER& slot) +    LLBoundListener connectPassedFilter(const LLEventListener& slot)      {          // see comments in connectChanged() -        return LLEventDetail::visit_and_connect(slot, -                                  boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl, -                                              this, -                                              _1)); +        return connectPassedFilterImpl(slot);      } -    template <typename LISTENER> -	LLBoundListener connectFailedFilter(const LISTENER& slot) +    LLBoundListener connectFailedFilter(const LLEventListener& slot)      {          // see comments in connectChanged() -        return LLEventDetail::visit_and_connect(slot, -                                  boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl, -                                              this, -                                              _1)); +        return connectFailedFilterImpl(slot);      }  	// use this when items change or to add a new one diff --git a/indra/test/llevents_tut.cpp b/indra/test/llevents_tut.cpp index 9ff0f5086d..a8a3188249 100644 --- a/indra/test/llevents_tut.cpp +++ b/indra/test/llevents_tut.cpp @@ -492,196 +492,60 @@ void events_object::test<10>()  	heaptest.stopListening("temp");  } -template<> template<> -void events_object::test<11>() -{ -	set_test_name("listen(boost::bind(...weak_ptr...))"); -	// listen() detecting weak_ptr<TempListener> in boost::bind() object -	bool live = false; -	LLEventPump& heaptest(pumps.obtain("heaptest")); -	LLBoundListener connection; -	ensure("default state", !connection.connected()); -	{ -		boost::shared_ptr<TempListener> newListener(new TempListener("heap", live)); -		newListener->reset(); -		ensure("TempListener constructed", live); -		connection = heaptest.listen(newListener->getName(), -									 boost::bind(&Listener::call,  -												 weaken(newListener),  -												 _1)); -		ensure("new connection", connection.connected()); -		heaptest.post(1); -		check_listener("received", *newListener, 1); -	} // presumably this will make newListener go away? -	// verify that -	ensure("TempListener destroyed", !live); -	ensure("implicit disconnect", !connection.connected()); -	// now just make sure we don't blow up trying to access a freed object! -	heaptest.post(2); -} - -template<> template<> -void events_object::test<12>() -{ -	set_test_name("listen(boost::bind(...shared_ptr...))"); -	/*==========================================================================*| -	// DISABLED because I've made this case produce a compile error. -	// Following the error leads the disappointed dev to a comment -	// instructing her to use the weaken() function to bind a weak_ptr<T> -	// instead of binding a shared_ptr<T>, and explaining why. I know of -	// no way to use TUT to code a repeatable test in which the expected -	// outcome is a compile error. The interested reader is invited to -	// uncomment this block and build to see for herself. - -	// listen() detecting shared_ptr<TempListener> in boost::bind() object -	bool live = false; -	LLEventPump& heaptest(pumps.obtain("heaptest")); -	LLBoundListener connection; -	std::string listenerName("heap"); -	ensure("default state", !connection.connected()); -	{ -		boost::shared_ptr<TempListener> newListener(new TempListener(listenerName, live)); -		ensure_equals("use_count", newListener.use_count(), 1); -		newListener->reset(); -		ensure("TempListener constructed", live); -		connection = heaptest.listen(newListener->getName(), -									 boost::bind(&Listener::call, newListener, _1)); -		ensure("new connection", connection.connected()); -		ensure_equals("use_count", newListener.use_count(), 2); -		heaptest.post(1); -		check_listener("received", *newListener, 1); -	} // this should make newListener go away... -	// Unfortunately, the fact that we've bound a shared_ptr by value into -	// our LLEventPump means that copy will keep the referenced object alive. -	ensure("TempListener still alive", live); -	ensure("still connected", connection.connected()); -	// disconnecting explicitly should delete the TempListener... -	heaptest.stopListening(listenerName); -#if 0   // however, in my experience, it does not. I don't know why not. -	// Ah: on 2009-02-19, Frank Mori Hess, author of the Boost.Signals2 -	// library, stated on the boost-users mailing list: -	// http://www.nabble.com/Re%3A--signals2--review--The-review-of-the-signals2-library-(formerly-thread_safe_signals)-begins-today%2C-Nov-1st-p22102367.html -	// "It will get destroyed eventually. The signal cleans up its slot -	// list little by little during connect/invoke. It doesn't immediately -	// remove disconnected slots from the slot list since other threads -	// might be using the same slot list concurrently. It might be -	// possible to make it immediately reset the shared_ptr owning the -	// slot though, leaving an empty shared_ptr in the slot list, since -	// that wouldn't invalidate any iterators." -	ensure("TempListener destroyed", ! live); -	ensure("implicit disconnect", ! connection.connected()); -#endif  // 0 -	// now just make sure we don't blow up trying to access a freed object! -	heaptest.post(2); -|*==========================================================================*/ -} -  class TempTrackableListener: public TempListener, public LLEventTrackable  {  public: -TempTrackableListener(const std::string& name, bool& liveFlag): -	TempListener(name, liveFlag) -{} +    TempTrackableListener(const std::string& name, bool& liveFlag): +        TempListener(name, liveFlag) +    {}  };  template<> template<> -void events_object::test<13>() -{ -set_test_name("listen(boost::bind(...TempTrackableListener ref...))"); -bool live = false; -LLEventPump& heaptest(pumps.obtain("heaptest")); -LLBoundListener connection; +void events_object::test<11>()  { -	TempTrackableListener tempListener("temp", live); -	ensure("TempTrackableListener constructed", live); -	connection = heaptest.listen(tempListener.getName(), -								 boost::bind(&TempTrackableListener::call, -											 boost::ref(tempListener), _1)); -	heaptest.post(1); -	check_listener("received", tempListener, 1); -} // presumably this will make tempListener go away? -// verify that -ensure("TempTrackableListener destroyed", ! live); -ensure("implicit disconnect", ! connection.connected()); -// now just make sure we don't blow up trying to access a freed object! -heaptest.post(2); +    set_test_name("listen(boost::bind(...TempTrackableListener ref...))"); +    bool live = false; +    LLEventPump& heaptest(pumps.obtain("heaptest")); +    LLBoundListener connection; +    { +        TempTrackableListener tempListener("temp", live); +        ensure("TempTrackableListener constructed", live); +        connection = heaptest.listen(tempListener.getName(), +                                     boost::bind(&TempTrackableListener::call, +                                                 boost::ref(tempListener), _1)); +        heaptest.post(1); +        check_listener("received", tempListener, 1); +    } // presumably this will make tempListener go away? +    // verify that +    ensure("TempTrackableListener destroyed", ! live); +    ensure("implicit disconnect", ! connection.connected()); +    // now just make sure we don't blow up trying to access a freed object! +    heaptest.post(2);  }  template<> template<> -void events_object::test<14>() -{ -set_test_name("listen(boost::bind(...TempTrackableListener pointer...))"); -bool live = false; -LLEventPump& heaptest(pumps.obtain("heaptest")); -LLBoundListener connection; +void events_object::test<12>()  { -	TempTrackableListener* newListener(new TempTrackableListener("temp", live)); -	ensure("TempTrackableListener constructed", live); -	connection = heaptest.listen(newListener->getName(), -								 boost::bind(&TempTrackableListener::call, -											 newListener, _1)); -	heaptest.post(1); -	check_listener("received", *newListener, 1); -	// explicitly destroy newListener -	delete newListener; -} -// verify that -ensure("TempTrackableListener destroyed", ! live); -ensure("implicit disconnect", ! connection.connected()); -// now just make sure we don't blow up trying to access a freed object! -heaptest.post(2); +    set_test_name("listen(boost::bind(...TempTrackableListener pointer...))"); +    bool live = false; +    LLEventPump& heaptest(pumps.obtain("heaptest")); +    LLBoundListener connection; +    { +        TempTrackableListener* newListener(new TempTrackableListener("temp", live)); +        ensure("TempTrackableListener constructed", live); +        connection = heaptest.listen(newListener->getName(), +                                     boost::bind(&TempTrackableListener::call, +                                                 newListener, _1)); +        heaptest.post(1); +        check_listener("received", *newListener, 1); +        // explicitly destroy newListener +        delete newListener; +    } +    // verify that +    ensure("TempTrackableListener destroyed", ! live); +    ensure("implicit disconnect", ! connection.connected()); +    // now just make sure we don't blow up trying to access a freed object! +    heaptest.post(2);  } -class TempSharedListener: public TempListener, -public boost::enable_shared_from_this<TempSharedListener> -{ -public: -TempSharedListener(const std::string& name, bool& liveFlag): -	TempListener(name, liveFlag) -{} -}; - -template<> template<> -void events_object::test<15>() -{ -	set_test_name("listen(boost::bind(...TempSharedListener ref...))"); -#if 0 -bool live = false; -LLEventPump& heaptest(pumps.obtain("heaptest")); -LLBoundListener connection; -{ -	// We MUST have at least one shared_ptr to an -	// enable_shared_from_this subclass object before -	// shared_from_this() can work. -	boost::shared_ptr<TempSharedListener> -		tempListener(new TempSharedListener("temp", live)); -	ensure("TempSharedListener constructed", live); -	// However, we're not passing either the shared_ptr or its -	// corresponding weak_ptr -- instead, we're passing a reference to -	// the TempSharedListener. -/*==========================================================================*| -	 std::cout << "Capturing const ref" << std::endl; -	 const boost::enable_shared_from_this<TempSharedListener>& cref(*tempListener); -	 std::cout << "Capturing const ptr" << std::endl; -	 const boost::enable_shared_from_this<TempSharedListener>* cp(&cref); -	 std::cout << "Capturing non-const ptr" << std::endl; -	 boost::enable_shared_from_this<TempSharedListener>* p(const_cast<boost::enable_shared_from_this<TempSharedListener>*>(cp)); -	 std::cout << "Capturing shared_from_this()" << std::endl; -	 boost::shared_ptr<TempSharedListener> sp(p->shared_from_this()); -	 std::cout << "Capturing weak_ptr" << std::endl; -	 boost::weak_ptr<TempSharedListener> wp(weaken(sp)); -	 std::cout << "Binding weak_ptr" << std::endl; -|*==========================================================================*/ -	connection = heaptest.listen(tempListener->getName(), -								 boost::bind(&TempSharedListener::call, *tempListener, _1)); -	heaptest.post(1); -	check_listener("received", *tempListener, 1); -} // presumably this will make tempListener go away? -// verify that -ensure("TempSharedListener destroyed", ! live); -ensure("implicit disconnect", ! connection.connected()); -// now just make sure we don't blow up trying to access a freed object! -heaptest.post(2); -#endif // 0 -}  } // namespace tut  | 
