What Happens to an Stl Iterator After Erasing It in VS, Unix/Linux

What happens to an STL iterator after erasing it in VS, UNIX/Linux?

Yes, if you erase an iterator, that iterator gets a so-called singular value, which means it doesn't belong to any container anymore. You can't increment, decrement or read it out/write to it anymore. The correct way to do that loop is:

for(map<T, S*>::iterator it = T2pS.begin(); it != T2pS.end(); T2pS.erase(it++)) {
// wilhelmtell in the comments is right: no need to check for NULL.
// delete of a NULL pointer is a no-op.
if(it->second != NULL) {
delete it->second;
it->second = NULL;
}
}

For containers that could invalidate other iterators when you erase one iterator, erase returns the next valid iterator. Then you do it with

it = T2pS.erase(it)

That's how it works for std::vector and std::deque, but not for std::map or std::set.

STL How to save iterator after erase()

When vector<int>::iterator oldIter = iter; is executed, Does oldIter
create a new iterator object?

Yes.

Why does the value of the iterator remain the same after incrementing
it?

It doesn't. What made you conclude that it does? Your printf statements? Those are invalid. printf does not know how to handle vector iterators. Your calls to it are undefined behavior.

What is a good way to erase a node without losing the location of the
iterator?

Capture the return value of the erase call.

iter = vContainer.erase(iter);

Finally, a trivial question. I tried cout << iter; but it does not
work. Why is that?

Because there is no operator<< overload which takes an std::ostream on the left, and a vector iterator on the right. And unlike printf, std::ostream::operator<< is typesafe, so you will get a compile time error, instead of runtime undefined behavior.

Problem with std::map::iterator after calling erase()

Erasing an element of a map invalidates iterators pointing to that element (after all that element has been deleted). You shouldn't reuse that iterator.

Since C++11 erase() returns a new iterator pointing to the next element, which can be used to continue iterating:

it = mymap.begin();
while (it != mymap.end()) {
if (something)
it = mymap.erase(it);
else
it++;
}

Before C++11 you would have to manually advance the iterator to the next element before the deletion takes place, for example like this:

mymap.erase(it++);

This works because the post-increment side-effect of it++ happens before erase() deletes the element. Since this is maybe not immediately obvious, the C++11 variant above should be preferred.

Erasing while iterating an std::list

The idiomatic way to write that loop would be:

for (auto i = list.begin(); i != list.end();) {
if (condition)
i = list.erase(i);
else
++i;
}

You can do the same thing with a set, multiset, map, or multimap. For these containers you can erase an element without affecting the validity to any iterators to other elements. Other containers like vector or deque are not so kind. For those containers only elements before the erased iterator remain untouched. This difference is simply because lists store elements in individually allocated nodes. It's easy to take one link out. vectors are contiguous, taking one element out moves all elements after it back one position.

Your loop is broken because you erase the element at i on some given condition. i is no longer a valid iterator after that call. Your for loop then increments i, but i is not valid. Hell upon earth ensues. This is the exact situation that is why erase returns the iterator to the element after what was erased... so you can continue traversing the list.

You could also use list::remove_if:

list.remove_if([](auto& i) { return i > 10; });

In the lambda, return true if the element should be removed. In this example, it would remove all elements greater than 10.

iterators after element deletion in cpp

i guess what you are looking for is iterator invalidation: https://www.geeksforgeeks.org/iterator-invalidation-cpp/#:~:text=Resizing-,a.,it%20is%20supposed%20to%20point.
check this link.

The summary is: if you delete element in vector, all the iterators pointing to the elements after deleted element gets changed. The iterator to the deleted element gets invalidated. Sometimes the program crashes and sometimes it just shows unpredictable answer.

the rules are different for other containers/sequence.

What is iterator invalidation?

  1. Iterators are glorified pointers. Iterator invalidation is a lot like pointer invalidation; it means it suddenly points to junk data.

  2. Because it's very natural but wrong to do things like this:

    for(iterator it = map.begin(); it != map.end(); ++it) {
    map.erase(it->first);
    // whoops, now map has been restructured and iterator
    // still thinks itself is healthy
    }
  3. Because that error right there? No compiler error, no warning, you lose. You just have to be trained well enough to watch for them and prevent them. Very insidious bugs if you don't know what you're doing. One of the design philosophies of C++ is speed over safety. The runtime check that would lead iterator invalidation to an exception instead of unspecified behavior is too expensive, in the view of C++ language designers.

You should be on high alert when you are iterating over a data structure and modifying structure itself, instead of merely the objects held in them. At that point you should probably run to the documentation and check whether the operation was illegal.

Erase set iterator value and increment iterator

When you call

myset.erase(it++);

A couple things happen. First it++ gets evaluated before it is passed to the function. When you evaluate it++ the result of that is it and that is what gets passed to the function. So your function gets the value of it but the value of it in the call site is what it is after being incremented. That means when erase erases the element the iterator points to it is erasing what the old iterator points to that you no longer have. This is a completely valid and safe way to erase an element from a set.

As an alternative, starting in C++11, erase returns the next valid iterator so you could use

it = myset.erase(it);

and it will have the same effect.

Can you remove elements from a std::list while iterating through it?

You have to increment the iterator first (with i++) and then remove the previous element (e.g., by using the returned value from i++). You can change the code to a while loop like so:

std::list<item*>::iterator i = items.begin();
while (i != items.end())
{
bool isActive = (*i)->update();
if (!isActive)
{
items.erase(i++); // alternatively, i = items.erase(i);
}
else
{
other_code_involving(*i);
++i;
}
}


Related Topics



Leave a reply



Submit