Please consider the following scenario:
map(T,S*) & GetMap(); //Forward decleration
map(T, S*) T2pS = GetMap();
for(map(T, S*)::iterator it = T2pS.begin(); it != T2pS.end(); ++it)
{
if(it->second != NULL)
{
delete it->second;
it->second = NULL;
}
T2pS.erase(it);
//In VS2005, after the erase, we will crash on the ++it of the for loop.
//In UNIX, Linux, this doesn't crash.
}//for
It seems to me that in VS2005, after the "erase", the iterator will be equal to end(), hence the crash while trying to increment it. Are there really differences between compilers in the behavior presented here? If so, what will the iterator after the "erase" equal to in UNIX/Linux?
Thanks...
I think if you modify the collection you invalidate your iterator. You can't rely on the behavior, as you found out.
After you call
erase
on an iterator into astd::map
, it is invalidated. This means that you cannot use it. Attempting to use it (e.g. by incrementing it) is invalid and can cause anything to happen (including a crash). For astd::map
, callingerase
on an iterator does not invalidate any other iterator so (for example) after this call, (so long asit
was notT2pS.end()
), it will be valid:Of course, if you use this approach, you won't want to unconditionally increment
it
in the for loop.For this example, though, why bother to erase in the for loop? Why not just call T2pS.clear() at the end of the loop.
On the other hand, it looks like you have a raw pointer 'on the right' of the map, but the map appears to own the pointed to object. In this case, why not make the thing on the right of the map some sort of smart pointer, such as std::tr1::shared_ptr?
[Incidentally, I don't see any template parameters to
map
. Have you typedef'ed a specific instantiation ofstd::map
asmap
in the local namespace?]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 containers that could invalidate other iterators when you erase one iterator,
erase
returns the next valid iterator. Then you do it withThat's how it works for
std::vector
andstd::deque
, but not forstd::map
orstd::set
.See this: