tags:

views:

518

answers:

4

Hi,

I'm porting a medium-sized C++ project from Visual Studio 2005 to MacOS, XCode / GCC 4.0.

One of the differences I have just stumbled across has to do with erasing an element from a map. In Visual Studio I could erase an element specified by an iterator and assign the return value to the iterator to get the position of the next element. This way the iterator would not point to some invalid address after erasing.

In other words, in Visual Studio I could do this:

itor=m_ResourceMap.erase(itor);

In GCC 4.0, the erase function returns void, so I can't do that. Does that mean that the following map elements are shifted one backwards, so the iterator points automatically to the next element, or does that mean that I have to increment the iterator afterwards? The online STL Documentation is not very concise on the subject and XCode does not seem to have any.

Thanks for your help,

Adrian

+10  A: 

No. You have to increment the iterator before erasing. Like this

m_ResourceMap.erase(itor++);

The iterator is invalidated by the erase, so you can't increment it afterwards.

jpalecek
I'm trying to make sense of the syntax. the itor++ is a postfix increment, so it erases itor, and then it should be invalid anyways, should it not?
Calyth
Postfix: increment *and then* return a value of what the iterator used to point to. This value is what gets erased.
Max Lybbert
+2  A: 

By the look of things gcc is following the STL standard so I guess you'll have to change your code.

void erase(iterator pos)     Associative Container  Erases the element pointed to by pos.
Douglas Leeder
A link to where you quoted that from would be useful.
Mark Ransom
Certainly I have to change the code, but how? That was the actual scope of my question...
Adrian Grigore
http://www.sgi.com/tech/stl/Map.html and http://www.cppreference.com/wiki/stl/map/erase seem to agree on this Mark.
Andy
A: 

jpalecek: Thanks for your reply! But are you sure there really is a difference between

m_ResourceMap.erase(itor++);

and

m_ResourceMap.erase(itor); ++itor;

In other words, does the postincrement really take place before erase(itor) is executed? This might be an academic question in this case, but I thought that this wasn't the case and it could backfire in other instances (e.g. when calling functions by reference and post-incrementing the argument).

Thanks,

Adrian

Adrian Grigore
You really do need the postincrement here. itor++ increments itor and then returns its old value, which is then used as the argument to erase. Your second version is bad because erase invalidates itor, and you can't increment an invalid iterator.
Kristo
Kristo is right. Incrementing the iterator after executing erase() will probably try to follow some pointers which will no longer be pointing to valid addresses and your application will crash.
Gorpik
Postincrement guarantees that it will return what the value used to be. However, if you increment a variable several times before the semicolon there is no guarantee what order those increments happen in. "int j = ++++i++++;" will assign j different values on different platforms/compilers.
Max Lybbert
thanks for the clarification, guys!
Adrian Grigore
A: 

I believe that the DinkumWare implementation of the C++ standard library implementation of erase() is defined to return the iterator after the element that is to be removed. This bit me as well and, when I asked DinkumWare about it, they said that it was a "conforming extension".

There are some STL containers (vectors for instance) that, when you perform insert or erase operations, can tend to invalidate all of the iterators for that container. I cannot recall if the map is one of those but, if it is, there is a potentially insidious vulnerability to your method of erasing map elements in a loop.

Jon Trauntvein
Map won't invalidate iterators on either insert or erase. http://www.sgi.com/tech/stl/Map.html
Mark Ransom