Summary of C + + iterator invalidation

Source: Internet
Author: User

1. For a sequential container (such as Vector,deque), the sequence container is an array container, and deleting the current iterator invalidates the iterator of all subsequent elements. This is because Vetor,deque uses contiguous allocated memory, and deleting an element causes all subsequent elements to move forward one position. So it is not possible to use erase (iter++) way, fortunately the erase method can return to the next valid iterator.

for (iter = Cont.begin (); ITER! = Cont.end ();) {   (*it)->dosomething ();   if (Shoulddelete (*iter))      iter = Cont.erase (ITER);  Erase delete element, return next iterator   else      ++iter;}

Iterator invalidation:

void Vectortest () {    vector<int> container;    for (int i = 0; i < i++)    {        container.push_back (i);    }     Vector<int>::iterator iter;     for (iter = Container.begin (); ITER! = Container.end (); iter++)    {            if (*iter > 3)              container.erase (ITER); c10/>} for      (iter = Container.begin (); ITER! = Container.end (); iter++)    {            Cout<<*iter<<endl ;    }}

The error is: Vectoriterator not incrementable.

Bottom Source:

operator+ + (int)     {=* This;      ++*this;      return (_tmp);      }

The iterator executes the + + operation times wrong! An iterator that has failed can no longer be self-increasing.

For a sequence container, such as a vector, deleting the current iterator will invalidate the iterator of all subsequent elements. This is because sequential container memory is continuously allocated (allocating an array as memory), and deleting an element causes all subsequent elements to move forward one position. (an element is removed and all elements behind it are moved, so iter++, which is already pointing to unknown memory).

However, the erase method can return to the next valid iterator. So the code to make the following changes, OK.

void Vectortest () {    vector<int> container;    for (int i = 0; i < i++)    {        container.push_back (i);    }     Vector<int>::iterator iter;     for (iter = Container.begin (); ITER! = Container.end ();)    {            if (*iter > 3) {iter = Container.erase (ITER);} else {iter + +;}     }      for (iter = Container.begin (); ITER! = Container.end (); iter++)    {            cout<<*iter<<endl;    }}

Summary: Vector is a sequential container, in memory is a contiguous memory, when the deletion of an element, in-memory data will be moved to ensure that the data compact. So when you delete a data, the address of the other data changes, and the previously acquired iterator does not have access to the correct data based on the original information.

So in order to prevent vector iterators from failing, the following methods are commonly used:

for (iter = Container.begin (); ITER! = Container.end ();)    {            if (*iter > 3)              iter = Container.erase (ITER);    The return value of erase is the iterator that deletes the next element of the element            else{                iter++;}    }

This removes the element after the ITER point and returns an iterator to the next element, which is a new, valid iterator after the vector memory adjustment.

1. For associative containers (such as map, Set,multimap,multiset), deleting the current iterator will only invalidate the current iterator, as long as the current iterator is incremented at erase. This is because containers such as map are implemented using a red-black tree, and inserting and deleting a node does not affect other nodes. The erase iterator is only invalidated by the iterator of the deleted element, but the return value is void, so the iterator is removed in the erase (iter++) manner.

for (iter = Cont.begin (); It! = Cont.end ();) {(*iter)->dosomething ();   if (Shoulddelete (*iter)) cont.erase (iter++); else ++iter;}      void Maptest () {map<int, string> dataMap;             for (int i = 0; i < i++) {string strvalue = ' Hello, world ';            StringStream SS;            ss<<i;            String Tmpstrcount;            ss>>tmpstrcount;            strvalue + = Tmpstrcount;    Datamap.insert (Make_pair (i, strvalue));     } cout<< "The Map element content is:" <<endl;    Map<int, String>::iterator iter;            for (iter = Datamap.begin (); ITER! = Datamap.end (); iter++) {int nkey = iter->first;            string strvalue = iter->second;    cout<<strvalue<<endl;    } cout<< "Content start Delete:" <<endl;    The erase operation throws an iterator invalidation for (iter = Datamap.begin (); ITER! = Datamap.end (); iter++)            {int nkey = iter->first; String strvalue = iter->second;    if (nkey% 2 = = 0) {datamap.erase (ITER); }/* cout<<iter->second<<endl;*/}}

  

Error:

Analysis: After Datamap.erase (ITER), ITER has been invalidated, so ITER can not be self-increasing, that is, iter++ will be a bug. The solution is to increase your self before ITER fails.

void Maptest () {map<int, string> dataMap;             for (int i = 0; i < i++) {string strvalue = ' Hello, world ';            StringStream SS;            ss<<i;            String Tmpstrcount;            ss>>tmpstrcount;            strvalue + = Tmpstrcount;    Datamap.insert (Make_pair (i, strvalue));     } cout<< "The Map element content is:" <<endl;    Map<int, String>::iterator iter;            for (iter = Datamap.begin (); ITER! = Datamap.end (); iter++) {int nkey = iter->first;            string strvalue = iter->second;    cout<<strvalue<<endl;    } cout<< "Content start Delete:" <<endl;    The erase operation throws an iterator invalidation for (iter = Datamap.begin (); ITER! = Datamap.end ();)            {int nkey = iter->first;            string strvalue = iter->second;    if (nkey% 2 = = 0) {datamap.erase (iter++); auto A = iter;   } else {iter + +; }    }} 

Resolution: Datamap.erase (iter++); This sentence is divided into three steps, the first to transfer the value of ITER to erase inside, and then the ITER since the increase, and then execute erase, so ITER has been self-increased before the failure.

Map is an associative container, with red black tree or balanced binary tree organization data, although the deletion of an element, the whole tree will also be adjusted to conform to the specification of red black tree or binary tree, but the address of a single node in memory does not change, the change is the point between the nodes of the relationship.

Therefore, in order to prevent the iterator from being invalidated in the map, the following methods are commonly used when there is a delete operation:

for (iter = Datamap.begin (); ITER! = Datamap.end ();)    {         int nkey = iter->first;         string strvalue = iter->second;          if (nkey% 2 = = 0)         {               Map<int, string>::iterator tmpiter = iter;       iter++;               Datamap.erase (tmpiter);               Datamap.erase (iter++) This line          }else {      iter++;         }   }

  

Map<int, String>::iterator tmpiter =iter; iter++;

Datamap.erase (Tmpiter);

The point is to keep the node iterator you want to delete, then make ITER down a meaningful node, and then delete the node.

So at the end of this operation, ITER points to the next meaningful node, which does not fail.

In fact, these three words can be used in a sentence instead, that is datamap.erase (iter++);

The explanation is to let ITER refer to the next valid node, but the original ITER copy is returned to the erase function. This may be related to the syntax of the + + operation itself.

But the function is the same as above.

Summary: The iterator failure is divided into three cases, is also not three data structure consideration, respectively, the array type, the chain table type, the tree type data structure.

Array-type data structure: The elements of this data structure are allocated in contiguous memory, insert and erase operations, will make the deletion point and the insertion point after the element moved position, so that the insertion point and deleted after the iterator all invalidated, that is, insert (*iter) (or erase (* ITER), and then in iter++, is meaningless. Workaround: The return value of erase (*iter) is the value of the next valid iterator. ITER =cont.erase (ITER);

Linked-list data structures: For a list-type structure, a discontinuous allocation of memory is used, and the delete operation invalidates the iterator that points to the delete location, but does not invalidate the other iterators. Workaround two, erase (*iter) returns the value of the next valid iterator, or erase (iter++ ).

Tree data structure: Use a red-black tree to store the information, the insertion does not invalidate any iterators, and the delete operation invalidates the iterator that points to the delete position, but does not invalidate the other iterators. The erase iterator is simply invalidated by the iterator of the deleted element, but the return value is void, so use erase (iter+ +) to remove the iterator.

Note: The iterator after erase (ITER) is completely invalidated, and the iterator ITER cannot participate in any operations, including Iter++,*ite

Summary of C + + iterator invalidation

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.