diff options
author | Jan Holesovsky <kendy@collabora.com> | 2013-12-21 17:26:01 +0100 |
---|---|---|
committer | Jan Holesovsky <kendy@collabora.com> | 2013-12-21 17:29:20 +0100 |
commit | c8b624329caed68550fcb1fe197c8fa8107d079b (patch) | |
tree | 253d7415cd79b0551339ba8ce49bb7451392752d /svl/source/notify | |
parent | 5527a867996c54fa80139f83fab7286c37630f9c (diff) |
Don't call EndListening() on already destructed listeners.
Change-Id: I9bda35f2246de9d37077dda33c710b89ee008e5a
Diffstat (limited to 'svl/source/notify')
-rw-r--r-- | svl/source/notify/broadcast.cxx | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/svl/source/notify/broadcast.cxx b/svl/source/notify/broadcast.cxx index 3575c7fb4ef1..50d68a98d066 100644 --- a/svl/source/notify/broadcast.cxx +++ b/svl/source/notify/broadcast.cxx @@ -35,18 +35,6 @@ public: } }; -class EndListeningHandler : std::unary_function<SvtListener*, void> -{ - SvtBroadcaster& mrBC; -public: - EndListeningHandler( SvtBroadcaster& rBC ) : mrBC(rBC) {} - - void operator() ( SvtListener* p ) - { - p->EndListening(mrBC); - } -}; - class NotifyHandler : std::unary_function<SvtListener*, void> { SvtBroadcaster& mrBC; @@ -81,9 +69,15 @@ void SvtBroadcaster::Add( SvtListener* p ) void SvtBroadcaster::Remove( SvtListener* p ) { - if (mbAboutToDie || mbDisposing) + if (mbDisposing) return; + if (mbAboutToDie) + { + maDestructedListeners.push_back(p); + return; + } + Normalize(); std::pair<ListenersType::iterator,ListenersType::iterator> r = std::equal_range(maListeners.begin(), maListeners.end(), p); @@ -107,8 +101,27 @@ SvtBroadcaster::~SvtBroadcaster() mbDisposing = true; Broadcast( SfxSimpleHint(SFX_HINT_DYING) ); - // unregister all listeners. - std::for_each(maListeners.begin(), maListeners.end(), EndListeningHandler(*this)); + // normalize the list of listeners than already asked for destruction + std::sort(maDestructedListeners.begin(), maDestructedListeners.end()); + ListenersType::iterator itUniqueEnd = std::unique(maDestructedListeners.begin(), maDestructedListeners.end()); + maDestructedListeners.erase(itUniqueEnd, maDestructedListeners.end()); + + // and the list of registered listeners too + Normalize(); + + // now when both lists are sorted, we can linearly unregister all + // listeners, with the exception of those that already asked to be removed + // during their own destruction + ListenersType::iterator dest(maDestructedListeners.begin()); + for (ListenersType::iterator it(maListeners.begin()); it < maListeners.end(); ++it) + { + // skip the destructed ones + while (dest != maDestructedListeners.end() && (*dest < *it)) + ++dest; + + if (dest == maDestructedListeners.end() || *dest != *it) + (*it)->EndListening(*this); + } } void SvtBroadcaster::Broadcast( const SfxHint &rHint ) @@ -133,4 +146,10 @@ bool SvtBroadcaster::HasListeners() const return !maListeners.empty(); } +void SvtBroadcaster::PrepareForDestruction() +{ + mbAboutToDie = true; + maDestructedListeners.reserve(maListeners.size()); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |