summaryrefslogtreecommitdiff
path: root/svl
diff options
context:
space:
mode:
authorJan Holesovsky <kendy@collabora.com>2013-12-21 17:26:01 +0100
committerJan Holesovsky <kendy@collabora.com>2013-12-21 17:29:20 +0100
commitc8b624329caed68550fcb1fe197c8fa8107d079b (patch)
tree253d7415cd79b0551339ba8ce49bb7451392752d /svl
parent5527a867996c54fa80139f83fab7286c37630f9c (diff)
Don't call EndListening() on already destructed listeners.
Change-Id: I9bda35f2246de9d37077dda33c710b89ee008e5a
Diffstat (limited to 'svl')
-rw-r--r--svl/source/notify/broadcast.cxx49
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: */