Kaydet (Commit) 6076a9a1 authored tarafından Oliver-Rainer Wittmann's avatar Oliver-Rainer Wittmann

118012 - methods <ScBroadcastAreaSlot::AreaBroadcast(..)> and…

118012 - methods <ScBroadcastAreaSlot::AreaBroadcast(..)> and <ScBroadcastAreaSlot::AreaBroadcastInRange(..)>

adapt stl-container interation in order to avoid destroyed iterators during iteration.
üst dd4360f4
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
// MARKER(update_precomp.py): autogen include statement, do not remove // MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx" #include "precompiled_sc.hxx"
#include <boost/mem_fn.hpp>
#include <sfx2/objsh.hxx> #include <sfx2/objsh.hxx>
#include <svl/listener.hxx> #include <svl/listener.hxx>
...@@ -279,15 +279,25 @@ sal_Bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) const ...@@ -279,15 +279,25 @@ sal_Bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) const
if (aBroadcastAreaTbl.empty()) if (aBroadcastAreaTbl.empty())
return sal_False; return sal_False;
sal_Bool bIsBroadcasted = sal_False; sal_Bool bIsBroadcasted = sal_False;
// issue 118012
// do not iterate on <aBoardcastAreaTbl> as its reveals that its iterators
// are destroyed during notification.
std::vector< ScBroadcastArea* > aCopyForIteration( aBroadcastAreaTbl.begin(), aBroadcastAreaTbl.end() );
std::for_each( aCopyForIteration.begin(), aCopyForIteration.end(), boost::mem_fn( &ScBroadcastArea::IncRef ) );
const ScAddress& rAddress = rHint.GetAddress(); const ScAddress& rAddress = rHint.GetAddress();
for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()); const std::vector< ScBroadcastArea* >::const_iterator aEnd( aCopyForIteration.end() );
aIter != aBroadcastAreaTbl.end(); /* increment in body */ ) std::vector< ScBroadcastArea* >::const_iterator aIter;
for ( aIter = aCopyForIteration.begin(); aIter != aEnd; ++aIter )
{ {
ScBroadcastArea* pArea = *aIter; ScBroadcastArea* pArea = *aIter;
// A Notify() during broadcast may call EndListeningArea() and thus // check, if copied item has been already removed from <aBroadcastAreaTbl>
// dispose this area if it was the last listener, which would if ( aBroadcastAreaTbl.find( pArea ) == aBroadcastAreaTbl.end() )
// invalidate the iterator, hence increment before call. {
++aIter; continue;
}
const ScRange& rAreaRange = pArea->GetRange(); const ScRange& rAreaRange = pArea->GetRange();
if (rAreaRange.In( rAddress)) if (rAreaRange.In( rAddress))
{ {
...@@ -298,6 +308,17 @@ sal_Bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) const ...@@ -298,6 +308,17 @@ sal_Bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) const
} }
} }
} }
// delete no longer referenced <ScBroadcastArea> instances
for ( aIter = aCopyForIteration.begin(); aIter != aEnd; ++aIter )
{
ScBroadcastArea* pArea = *aIter;
if ( !pArea->DecRef() )
{
delete pArea;
}
}
return bIsBroadcasted; return bIsBroadcasted;
} }
...@@ -308,14 +329,24 @@ sal_Bool ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange, ...@@ -308,14 +329,24 @@ sal_Bool ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange,
if (aBroadcastAreaTbl.empty()) if (aBroadcastAreaTbl.empty())
return sal_False; return sal_False;
sal_Bool bIsBroadcasted = sal_False; sal_Bool bIsBroadcasted = sal_False;
for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
aIter != aBroadcastAreaTbl.end(); /* increment in body */ ) // issue 118012
// do not iterate on <aBoardcastAreaTbl> as its reveals that its iterators
// are destroyed during notification.
std::vector< ScBroadcastArea* > aCopyForIteration( aBroadcastAreaTbl.begin(), aBroadcastAreaTbl.end() );
std::for_each( aCopyForIteration.begin(), aCopyForIteration.end(), boost::mem_fn( &ScBroadcastArea::IncRef ) );
const std::vector< ScBroadcastArea* >::const_iterator aEnd( aCopyForIteration.end() );
std::vector< ScBroadcastArea* >::const_iterator aIter;
for ( aIter = aCopyForIteration.begin(); aIter != aEnd; ++aIter )
{ {
ScBroadcastArea* pArea = *aIter; ScBroadcastArea* pArea = *aIter;
// A Notify() during broadcast may call EndListeningArea() and thus // check, if copied item has been already removed from <aBroadcastAreaTbl>
// dispose this area if it was the last listener, which would if ( aBroadcastAreaTbl.find( pArea ) == aBroadcastAreaTbl.end() )
// invalidate the iterator, hence increment before call. {
++aIter; continue;
}
const ScRange& rAreaRange = pArea->GetRange(); const ScRange& rAreaRange = pArea->GetRange();
if (rAreaRange.Intersects( rRange )) if (rAreaRange.Intersects( rRange ))
{ {
...@@ -326,6 +357,17 @@ sal_Bool ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange, ...@@ -326,6 +357,17 @@ sal_Bool ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange,
} }
} }
} }
// delete no longer referenced <ScBroadcastArea> instances
for ( aIter = aCopyForIteration.begin(); aIter != aEnd; ++aIter )
{
ScBroadcastArea* pArea = *aIter;
if ( !pArea->DecRef() )
{
delete pArea;
}
}
return bIsBroadcasted; return bIsBroadcasted;
} }
......
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