Summary of STL's erase of trap iterator failure problem

  • 2020-05-10 18:33:11
  • OfStack

The material below is collated from Internet& works.

Containers in STL are divided into two categories according to the way they are stored. The first category is containers that are stored in an array (e.g. vector, deque). The other is containers that are stored as discrete nodes (e.g., list, set, map). There are a few issues to be aware of when using the erase method to delete elements.

1. list set, map container

When using list, set, or map to traverse the removal of certain elements:

1.1 correct writing 1


std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{
   if( WillDelete( *itList) )
   {
      itList = List.erase( itList);
    }
    else
      itList++;
}

1.2 correct writing 2


std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{
   if( WillDelete( *itList) )
   {
     List.erase( itList++);
   }
   else
     itList++;
}

1.3 incorrect writing 1


std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); itList++)
{
  if( WillDelete( *itList) )
  {
     List.erase( itList);
  }
}

1.4 error 2


std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{
   if( WillDelete( *itList) )
   {
     itList = List.erase( ++itList);
   }
   else
     itList++;
}

1.5 analysis

Method 1: get the location of the next element by the return value of the erase method

Use method 2 correctly: use "++" to get the location of the next element before calling the erase method

Error using method 1: after calling the erase method, use "++" to get the location of the next element, since the location of the element is already there after calling the erase method

Is deleted. If the next location is retrieved from the old location, an exception will occur.

Wrong use method 2: ibid.

2. vector, deque container

When deleting elements through vector and deque, the position of the next element can also be obtained through the return value of erase:

2.1 correct writing


std::vector< int> Vec;
std::vector< int>::iterator itVec;
for( itVec = Vec.begin(); itVec != Vec.end(); )
{
 if( WillDelete( *itVec) )
 {
   itVec = Vec.erase( itVec);
  }
 else
   itList++;
}

2.2 pay attention to

Note: vector and deque cannot traverse deletions like the "use method 2 correctly" method above. Please refer to Effective STL clause 9 for the reason. Excerpt below:

1)   for associating containers (such as map, set, multimap,multiset), deleting the current iterator will only invalidate the current iterator, as long as the current iterator is increments at erase. This is because containers such as map are implemented using red-black trees, and the insertion and deletion of one node will not affect other nodes.


for (iter = cont.begin(); it != cont.end();)
{
(*iter)->doSomething();
if (shouldDelete(*iter))
 cont.erase(iter++);
else
 ++iter;
}

Since iter passes one copy to the erase method, iter++ will point to the next element.

2) for sequential containers (such as vector,deque), deleting the current iterator will invalidate the iterator of all subsequent elements. This is because vetor,deque USES continuously allocated memory, and removing one element causes all subsequent elements to move forward one location. Fortunately, the erase method returns the next valid iterator.


for (iter = cont.begin(); iter != cont.end();)
{
(*it)->doSomething();
if (shouldDelete(*iter))
 iter = cont.erase(iter); 
else
 ++iter;
}

3) for list, it USES discontinuous allocated memory, and its erase method will also return the next valid iterator, so the above two methods can be used.

3. Failure of the iterator

3.1 vector

Internal data structure: array.

The time required to access each element at random is constant.

The time required to add or remove elements at the end is independent of the number of elements, and the time required to add or remove elements at the middle or beginning varies linearly with the number of elements.

You can dynamically add or subtract elements, and memory management is done automatically, but programmers can use the reserve() member function to manage memory.

The iterator of vector fails when memory is reallocated (the elements it points to are no longer the same before and after the operation). When more than capacity() -size () elements are inserted into vector, memory is reallocated and all iterators fail. Otherwise, the iterator that points to any element after the current element will fail. When an element is deleted, the iterator that points to any element after the deleted element is invalidated.

3.2 deque

Internal data structure: array.

The time required to access each element at random is constant.

The time required to add elements at the beginning and end is independent of the number of elements, while the time required to add or remove elements in the middle varies linearly with the number of elements.

You can add or subtract elements dynamically, memory management is done automatically, and no member functions are provided for memory management.

Adding any element will invalidate the iterator of deque. Deleting an element in the middle of deque will invalidate the iterator. When an element is deleted from the head or tail of deque, only the iterator pointing to that element fails.

3.3 list

Internal data structure: bidirectional circular linked list.

You cannot access an element at random.

Can be bidirectional traversal.

The time required to add or remove elements at the beginning, end, and anywhere in between is constant.

You can add or subtract elements dynamically, and memory management is done automatically.

Adding any element does not invalidate the iterator. When an element is deleted, no iterator fails except the iterator that points to the currently deleted element.

3.4 slist

Internal data structure: unidirectional linked list.

Not bidirectional traversal, can only traverse from the front to the back.

Other features are similar to list.

3.5 stack

Adapter, which can convert any type of sequence container into a stack, generally using deque as the supported sequence container.

Elements can only be last in, first out (LIFO).

You cannot traverse the entire stack.

3.6 queue

Adapter, which can convert any type of sequence container to a queue, generally using deque as the supported sequence container.

Elements can only be first in first out (FIFO).

You cannot traverse the entire queue.

3.7 priority_queue

Adapter, which can convert any type of sequence container into a priority queue using vector as the underlying storage.

Only the first element can be accessed, and the entire priority_queue cannot be traversed.

The first element is always the one with the highest priority.

3.8 set

The keys are the same as the values.

Key only 1.

Elements are sorted in ascending order by default.

If the element pointed to by the iterator is deleted, the iterator fails. Anything else that adds or removes elements does not invalidate the iterator.

3.9 multiset

Keys can be more than 1.

Other features are the same as set.

3.10 hash_set

In comparison with set, the elements in it are not necessarily sorted, but assigned according to the hash function used, which provides a faster search speed (related to hash, of course).

Other features are the same as set.

3.11 hash_multiset

Keys can be more than 1.

Other features are the same as hash_set.

3.12 map

Key only 1.

Element default keys are arranged in ascending order.

If the element pointed to by the iterator is deleted, the iterator fails. Anything else that adds or removes elements does not invalidate the iterator.

3.13 multimap

Keys can be more than 1.

Other features are the same as map.

3.14 hash_map

In comparison with map, the elements in map are not sorted by key value, but assigned by the hash function used, which can provide faster search speed (also related to hash function, of course).

Other features are the same as map.

3.15 hash_multimap

Keys can be more than 1.

Other features are the same as hash_map.


Related articles: