cppcheck error : Dangerous iterator usage - c++

The code:
for(x=abc.begin();x!=abc.end();x++)
{
if(-----)
{
----
abc.erase(x);
}
}
And the error is :::
Dangerous iterator usage
After erase the iterator is invalid so dereferencing it or comparing it with another iterator is invalid.
what is the wrong usage in using erase function in the above code?

The itarator x is invalid after deleting the corresponding value from abc. This should fix it:
x = abc.begin();
while(x != abc.end())
{
if (-----)
{
----
x = abc.erase(x);
// skipped only to next item
}
else
{ // skip only to next item
++x;
}
}
The erase template functions of STL containers return the next element, or end().
Edit: Thanks for comment by templatetypedef.

You're using x as the control variable in the loop. Since it is invalidated by erase(), you cannot be sure that it is safe (or meaningful) to subsequently increment it at the top of the loop.

x is a pointer into abc. Once you've erased the item pointed to by x, what is x supposed to be pointing to and how is x++ supposed to work?

You said nothing about the container you are iterating on. On the type of the container depends which iterators are invalidated. For sure iterator to erased element is invalid, but for example in std::vector all iterators past erased element will be invalid (including end()). And for unknown reason although set::erase invalidates only iterator to erased element, it does not return the iterator to next element.
So with std::set:
while (x != abc.end()) // end() will not change and even can be stored
{
if (...)
abc.erase(x++); // increments before erasing
else
++x;
}

Related

rbegin() in std::list is never equal to an iterator pointing into the list?

Why does the following code crash?
int main(int argc, const char * argv[]) {
std::list<int> aList={1,2,3,4,5};
std::list<int>::reverse_iterator i=aList.rbegin();
i++;
i++;
assert(*i==3);//assertion passes as expected
while (i!=aList.rbegin()) { //never becomes false
aList.pop_back(); //segmentation fault
}
assert(*(aList.rbegin())==3);
return 0;
}
I assume rbegin will eventually equal to i and stop the loop; however not happening.
Note I did following workaround, still curios whats the wrong with the above code in first place
size_t differance =std::distance( aList.rbegin(),i);
while (differance >0) {
aList.pop_back();
differance--;
}
assert(*aList.rbegin()==3);
std::list::rbegin() returns an iterator that refers to the sentinel end-of-list node, but dereferences to the value stored in the prior node (5 in your case). This behavior applies to any reverse iterator of an std::list: the node you get a value from when dereferencing it a reverse iterator is the node prior to the node the iterator is actually pointing at.
Visualize it like this, in terms of which element is referenced by iterators:
rend() <-------- rbegin()
| |
1 2 3 4 5 (end)
| |
begin() --------> end()
This means that the iterator that dereferences to the value 3 is actually internally referring to the element with the value 4. When the value 4 is removed from the list, the iterator value stored in i becomes invalidated, and at that point you can't reason about its behavior. It's likely to be (and should be) not equal to every other iterator.
You can verify for yourself that this is the case by writing out the value of *(i.base()) when *i == 3. You will see that *(i.base()) == 4.
So your problem is not that rbegin() iterators are "never equal to an iterator pointing into the list," your problem is that you are removing the element that the iterator was internally pointing to and then trying to compare that now-invalidated iterator to rbegin().
Consider using aList.erase() instead of your loop. Since you want to remove from the element with the value 4 to the end of the array, i.base() already gives you an iterator that you can pass directly to aList.erase():
aList.erase(i.base(), aList.end());
Looks like you have it all reversed ,incrementing a reverse iterator moves it backward.
and pop_back() will invalidate an iterator to the last element, hence a segfault in your loop. You should do a pop_front() and check for (i !=rend())

c++ iterator comparison Assertion Failed

I have a list list<x> bar and an array of iterators list<x>::iterator foo[100] initialized all elements with bar.end().
I want to store pointers in foo to some elements in bar while I'm going to erase, insert and push_back elements into bar. For element insertion I have to check if a position in foo is empty or not:
if (foo[my_number] != bar.end())
//do something 1
else
//do something 2
I receive an error only in case the foo[my_number] is already pointing to a bar element. The if is true I got this error (if false, no problem):
Debug Assertion Failed!
Program: C:\Windows\system32\MSVCP120D.dll
File: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\list
Line: 289
Expression: list iterators incompatible
I read here that after insertion the bar.end() is not the same as before. However, my code doesn't fail if I push back elements and compare a bar.end and foo[k] = end. But fails to compare bar.end to foo[k] = bar.begin() + p (this bar element exist).
What am I missing? How can I overcome this problem? Should I re-actualize foo after I inserted elements?
insert or push_back operation in std::list does not invalidate iterators or references. erase invalidates iterators (and references) to the erased elements. The problem is caused by that you use iterator to erased element, after erase (or before), you should update this element iterator also in your array - preferable to end iterator.
The problem is that you should first find it, so before erase you might need to search it. How to you plan to keep synchronized your array and list?
Below is some example what you can and should not do:
std::list<int> lst;
std::vector<std::list<int>::iterator> arr;
// Init arr with end() iterator
arr.push_back(lst.end());
// Add new list element
lst.push_back(0);
// Remember where it is in arr
arr[0] = lst.begin();
// Compare it.
if ( arr[0] == lst.begin())
{
std::cout << "this is OK!\n";
}
lst.push_back(0);
if (arr[0] == lst.begin())
{
std::cout << "this is still OK!\n";
}
lst.erase(lst.begin());
//arr[0] = lst.end(); - without this, "list iterators incompatible" is issued by VS below
if (arr[0] == lst.begin())
{
// list iterators incompatible
std::cout << "This is WRONG!\n";
}
Erasing an element from a std::list invalidates iterators pointing to it (see here). So if you do erase from bar, be sure to remove the corresponding iterators from foo. All other std::list operations are supposed to keep existing iterators valid.
The link you found points to a question about std::vector which behaves differently with regard to iterator invalidation.

C++ - Vector iterator not incrementable error

I have myVector with some values of the type Texture_Map which is just an int.
I'm not erasing anything... I just want to insert a value in each even iteration.
Something like:
If I have this vector [1,2,3,4,5]
And my Texture_Map::TEXTURE_FLIP is 99, then my final vector should be:
[99,1,99,2,99,3,99,4,99,5]
After the first insert() I get the "Vector iterator not incrementable problem" error.
The code:
myVector.push_back(Texture_Map::TEXTURE_INIT);
for(unsigned int i = 0 ; i < m_max_pieces-2; i++)
myVector.push_back((Texture_Map::TextureID)i);
std::random_shuffle(myVector.begin(), myVector.end());
std::vector<Texture_Map::TextureID>::iterator it = myVector.begin();
for (it=myVector.begin(); it<myVector.end(); it++)
{
myVector.insert(it,Texture_Map::TEXTURE_FLIP);
}
Thanks!
As part of the consequence of using insert on a vector is that it:
Causes reallocation if the new size() is greater than the old capacity(). If the new size() is greater than capacity(), all iterators and references are invalidated. Otherwise, only the iterators and references before the insertion point remain valid. The past-the-end iterator is also invalidated.
The issue you're seeing is that you're attempting to increment an iterator which is no longer valid - it's past the insertion point, so it's invalidated. The solution here is to take advantage of that fact that insert returns an iterator:
iterator insert( iterator pos, const T& value );
Specifically:
Return value
1-2) Iterator pointing to the inserted value
So you want:
for (it=myVector.begin(); it<myVector.end(); it++) {
// now it will point to TEXTURE_FLIP
it = myVector.insert(it,Texture_Map::TEXTURE_FLIP);
// now it will point back to the original element
++it;
}

Why does one of the two programs cause "*** glibc detected *** double free or corruption" error while the other not?

According to valgrind, this problem is caused by the codes below.I want to remove the element in the list, which contains the same integer value as ref.
while(itr1!=list1.end())
{
if(itr1->num==ref)
{
list1.erase(itr1);
}
else
{itr1++;}
}
list1 is an STL list, the type of list element is NODE, which is a structrue. num is one of the integer element in NODE . itr1 is an iterator of list1. ref is an integer value.
But after I replace with the codes below, it's correct
for(;itr1!=list1.end();itr1++)
{
if(itr1->num==ref)
{
list1.erase(itr1);
itr1--;
}
}
I really couldn't see the difference between the two snippets.
I don't know whether you can figure out the problem with incomplete codes. If you need, I can post all the program. Thanks!
After an erase the iterator of the removed element is invalidated. The second code works because of luck, though this is undefined behaviour and the code should be considered buggy.
The problem is that you are not exiting the loop after erasing the element. Iterators pointing to an erased element are invalidated.
while(itr1!=list1.end())
{
if(itr1->num==ref)
{
list1.erase(itr1);
break;
}
else
{itr1++;}
}
Have you considered using remove_if?
It might be less efficient if you know that you have only one element with that value in the list (remove_if search all occurrencies).
Iterators are really pointers in disguise. When you erase through an iterator, that iterator becomes invalid; it is analogous to doing a delete or free(). The solution is the same as in classic C code:
// Classic C code for removing all nodes matching
// key_to_delete from doubly-linked list:
while (itr != list->null_node)
{
node *next = itr->next; // Calculate next node now, while itr is valid!
if (itr->data == key_to_delete) {
itr->prev->next = itr->next;
itr->next->prev = itr->prev;
list_node_free(itr);
}
itr = next; // Advance to previously calculated next node
}
The same concept in C++ with list container:
while (itr1 != list1.end())
{
std::list<whatever>::iterator next = itr1; // calculate next iterator now
next++; // while itr1 is valid
if (itr1->num == ref)
{
list1.erase(itr1);
}
itr1 = next;
}
The erase operation on a list iterator only invalidates that iterator (and all copies of it). It does not invalidate iterators pointing to other parts of the list. This is why the value of next survives the erasure and can be used.

vector iterators incompatible while erase from vector

I have a map which elements are vectors.I have to delete from these vectors all elements which are equal to special number num
std::map<size_t,std::vector<size_t> > myMap;
for (std::map<size_t,std::vector<size_t> >::iterator itMap = myMap.begin();itMap != myMap.end();++itMap )
{
for (std::vector<size_t>::iterator itVec = itMap->second.begin();itVec != itMap->second.end();)
{
auto itNextVec = itVec;
++itNextVec;
if (*itVec == num)
{
itMap->second.erase(itVec );
}
itVec = itNextVec;
}
}
The code causes run-time exepssion .In VS - vector iterators incompatible.
Can someone point what is the cause for that?
Thanks
std::vector::erase returns an iterator to the next position of the list, and so when you do an erase you should make your iterator equal to the returned value.
The only thing that you have to consider is that the returned iterator could be the end so you should check for that.
What I personally like to do is is after doing in an erase and I get the next iterator position, I go back to the previous position of the returned iterator and than call a continue on the for loop
Example:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> myInt;
myInt.push_back(1);myInt.push_back(2);myInt.push_back(3);
for(auto iter = myInt.begin();
iter != myInt.end();
++iter)
{
if(*iter == 1)
{
iter = myInt.erase(iter);
if(iter != myInt.begin())
{
iter = std::prev(iter);
continue;
}
}
std::cout << *iter << std::endl;
}
}
But doing an erase inside of a iterator loop is frowned upon because it invalidates the old iterator and that could cause a lot of issues if you didn't plan for them.
erasing will invalidate the iterator
Iterator validity
Iterators, pointers and references pointing to position (or first) and beyond are
invalidated, with all iterators, pointers and references to elements before position (or
first) are guaranteed to keep referring to the same elements they were referring to
before the call.
You can't trivially erase an item from a collection while iterating over it. Think a little about it, your removing what itVec "points" to, after the removal itVec no longer "points" to an element, so it no longer have a "next" pointer.
If you check e.g. this reference, you will see that the erase function returns an iterator to the next element. Continue the loop with this one (without increasing it of course).
Consider either using a different collection class than vector or creating a new vector with the desired items removed rather than removing from existing vector.