--- /dev/null
+// Avoid buggy code, that tries to erase elements, matching a
+// certain property from containers. Example:
+//
+// for (ResStore::iterator it = store.begin(); it != store.end(); ++it)
+// {
+// _pool.erase(*it);
+// }
+//
+// Problem: Removing an element from a container invalidates (at least)
+// all iterators pointing to it. Thus after erasing *it, it is
+// no longer valid. ++it has UNDEFINED BEHAVIOUR.
+
+// //////////////////////////////////////////////////////////////////////
+// Loop based algorithms (differs depending on the kind of container)
+// =====================
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Sequential container (vector string deque list): erase returns
+// a valid iterator to the next element.
+// //////////////////////////////////////////////////////////////////////
+
+ SeqContainer c;
+ for ( SeqContainer::iterator it = c.begin(); it != c.end(); /**/ )
+ {
+ if ( toBeRemoved( *it ) )
+ {
+ it = c.erase( it ); // valid next-iterator returned
+ }
+ else
+ ++it;
+ }
+
+
+// //////////////////////////////////////////////////////////////////////
+// Associative container (maps sets): erase returns void, but we can use
+// postfix increment, as ONLY iterators to the eased object get invalid:
+// //////////////////////////////////////////////////////////////////////
+
+ AssocContainer c;
+ for ( AssocContainer::iterator it = c.begin(); it != c.end(); /**/ )
+ {
+ if ( toBeRemoved( *it ) )
+ {
+ c.erase( it++ ); // postfix! Incrementing before erase
+ }
+ else
+ ++it;
+ }
+
+
+// //////////////////////////////////////////////////////////////////////
+// stl algorithms
+// ==============
+//
+// In case toBeRemoved above is actually a function/functor.
+// //////////////////////////////////////////////////////////////////////
+
+
+// //////////////////////////////////////////////////////////////////////
+// Sequential container (vector string deque): stl::remove_if,
+// does not erase elements, they are just moved to the containers
+// end, and an iterator to the 1st item to be 'removed' is returned.
+// //////////////////////////////////////////////////////////////////////
+
+ SeqContainer c;
+ c.erase( stl::remove_if( c.begin(), c.end(), toBeRemoved ),
+ c.end() );
+
+
+// //////////////////////////////////////////////////////////////////////
+// Sequential container (list): The above works too, but list has a
+// builtin remove/remove_if which is more efficient.
+// //////////////////////////////////////////////////////////////////////
+
+ list c;
+ c.remove_if( toBeRemoved );
+
+
+// //////////////////////////////////////////////////////////////////////
+// Associative container (maps sets): Actually the loop above is the most
+// efficient solution. There is an algorithm based solution, but it requires
+// copying all elements not to be removed ;(
+// //////////////////////////////////////////////////////////////////////
+
+ AssocContainer c;
+
+ AssocContainer keepItems;
+ stl::remove_copy_if( c.begin(), c.end(),
+ stl::inserter( keepItems, keepItems.end() ),
+ toBeRemoved );
+ c.swap( keepItems );
+
NameHash::erase( const PoolItem & item_r )
{
PoolTraits::ItemContainerT items = _store[item_r->name()];
- for (PoolTraits::iterator nit = items.begin();
- nit != items.end(); ++nit)
+ for ( PoolTraits::iterator nit = items.begin(); nit != items.end(); /**/ )
{
- if (*nit == item_r)
- items.erase( nit );
+ if ( *nit == item_r )
+ items.erase( nit++ ); // postfix! Incrementing before erase
+ else
+ ++nit;
}
}
{
CapSet caps = item_r->dep( cap_r );
//XXX << "storeDelete(" << item_r << ")" << endl;
- for (CapSet::iterator ic = caps.begin(); ic != caps.end(); ++ic) {
- PoolTraits::CapItemContainerT capitems = store_r[cap_r][ic->index()];
- for (PoolTraits::CapItemContainerT::iterator pos = capitems.begin();
- pos != capitems.end();)
- {
- PoolTraits::CapItemContainerT::iterator next = pos; ++next;
- if (pos->item == item_r)
- capitems.erase( pos );
- pos = next;
- }
- }
+ for ( CapSet::iterator ic = caps.begin(); ic != caps.end(); ++ic )
+ {
+ PoolTraits::CapItemContainerT capitems = store_r[cap_r][ic->index()];
+ for ( PoolTraits::CapItemContainerT::iterator pos = capitems.begin(); pos != capitems.end(); /**/ )
+ {
+ if ( pos->item == item_r )
+ capitems.erase( pos++ ); // postfix! Incrementing before erase
+ else
+ ++pos;
+ }
+ }
}
void CapHash::erase( const PoolItem & item_r )