diff options
-rw-r--r-- | include/svl/broadcast.hxx | 7 | ||||
-rw-r--r-- | svl/source/notify/broadcast.cxx | 49 |
2 files changed, 40 insertions, 16 deletions
diff --git a/include/svl/broadcast.hxx b/include/svl/broadcast.hxx index d122e02594c6..72ac3036cd28 100644 --- a/include/svl/broadcast.hxx +++ b/include/svl/broadcast.hxx @@ -70,10 +70,15 @@ public: * themselves from the broadcaster - the broadcaster will not broadcast * anything after the PrepareForDesctruction() call anyway. */ - void PrepareForDestruction() { mbAboutToDie = true; } + void PrepareForDestruction(); private: ListenersType maListeners; + + /// When the broadcaster is about to die, collect listeners that asked for removal. + ListenersType maDestructedListeners; + + /// Indicate that this broadcaster will be destructed (we indicate this on all ScColumn's broadcasters during the ScTable destruction, eg.) bool mbAboutToDie:1; bool mbDisposing:1; bool mbNormalized:1; 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: */ |