Recently in the project development, encountered an exception, after testing, found to be an iterator failure problem, so a little summed up a bit.
Vector iterator failure test:
Test procedure:
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);
}
for (iter = Container.begin (); ITER! = Container.end (); iter++)
{
cout<<*iter<<endl;
}
} The test results are as follows:
The result? Certainly wrong, the result should be 0,1,2,3.
After the follow-up to see the error situation:
The iterator executes the + + operation times wrong!
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, and deleting an element causes all subsequent elements to move forward one position. 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); The return value of the erase is the iterator that deletes the next element of the element
else{
iter++;
}
}
for (iter = Container.begin (); ITER! = Container.end (); iter++)
{
cout<<*iter<<endl;
}
} The results of the operation are as follows:
The result is correct.
Look at an example of a map,
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<< "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;
Erase operation throws 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;
}
}
Result Error:
See if the report is abnormal, and where to go with the error:
Invalid when accessing data based on iterators! Map/set Iterator not dereferencable
Iterators are not referenced.
The correct approach is to:
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<< "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;
for (iter = Datamap.begin (); ITER! = Datamap.end ();)
{
int nkey = iter->first;
string strvalue = iter->second;
if (nkey% 2 = = 0)
{
Datamap.erase (iter++);
}else
{
iter++;
}
if (iter! = Datamap.end ())
cout<<iter->second<<endl;
}
The result of the final output:
The program deletes the output one at a time, and the output ends smoothly.
To summarize:
A vector is a sequential container in which memory is contiguous, and when an element is deleted, the data in memory moves to ensure that the data is 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 the 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. Foolproof!
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++) that's okay.
}else
{
iter++;
}
}
which
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.
Reference: http://my.oschina.net/myspaceNUAA/blog/55053
Turn: STL iterator invalidation problem