Kaydet (Commit) c8b62432 authored tarafından Jan Holesovsky's avatar Jan Holesovsky

Don't call EndListening() on already destructed listeners.

Change-Id: I9bda35f2246de9d37077dda33c710b89ee008e5a
üst 5527a867
......@@ -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;
......
......@@ -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: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment