std::map iterator and clearing

K

Kelly Mandrake

I have been learning about STL's map class. I see that I can clear a
hashmap by useing the method clear, however I decided to try to clear
the hash with a for loop. Since erase can take an iterator as a
position I thought I could do something like this:

hashTable::iterator i;

for (i = phoneBook.begin(); i != phoneBook.end(); i++)
{
cout << i->first << endl;
phoneBook.erase(i);
}

I get an access violation, I think the reason is that the condition is
never false , and thus the loop continues to now access memory beyond
phoneBook. But I cannot see why. If i comment out the erase line I am
ok, but what I am trying to do is to clear the phoneBook. Without
useing clear method.

Could somebody give me a hint, is it true the condition is never false?
What could possibly be causeing that.
 
R

red floyd

Kelly said:
I have been learning about STL's map class. I see that I can clear a
hashmap by useing the method clear, however I decided to try to clear

hashmap is not a standard class.
the hash with a for loop. Since erase can take an iterator as a
position I thought I could do something like this:

hashTable::iterator i;

for (i = phoneBook.begin(); i != phoneBook.end(); i++)
{
cout << i->first << endl;
phoneBook.erase(i);

At this point, i is an invalid iterator. I suspect the correct code
should be:

for (i = phoneBook.begin(); i != phoneBook.end() ; )
{
cout << i->first.endl;
i = phoneBook.erase(i); // guess, don't know what
// hashmap::erase returns
}
 
R

red floyd

red said:
hashmap is not a standard class.



At this point, i is an invalid iterator. I suspect the correct code

Sorry, meant to say, i is invalid, so i++ has no meaning.
 
K

Kelly Mandrake

sorry, i forgot to say i typedefed hashmap like so

typedef map<string, string> hashTable;

unfortunately also when I try i = phoneBook.erase(i) I get no match for
'operator=' in 'i = (&phoneBook)->......

I think the reason is my implementation of STL returns void from erase,
this is my guess after reading an article about the difernt
implementations of STL. Actualy this code I wrote was a test because
im trying to port code writen for msvc.

is the reason i is invalid because i didnt mention my typedef? Because
it will compile if i comment out the line phoneBook.erase(i); it will
work fine I think i++ is ok in my case, but what exactly hapens when
erase is called? The documentation i found on microsft does not seem
to explain this.
 
R

red floyd

Kelly said:
sorry, i forgot to say i typedefed hashmap like so

typedef map<string, string> hashTable;

unfortunately also when I try i = phoneBook.erase(i) I get no match for
'operator=' in 'i = (&phoneBook)->......

I think the reason is my implementation of STL returns void from erase,
this is my guess after reading an article about the difernt
implementations of STL. Actualy this code I wrote was a test because
im trying to port code writen for msvc.

is the reason i is invalid because i didnt mention my typedef? Because
it will compile if i comment out the line phoneBook.erase(i); it will
work fine I think i++ is ok in my case, but what exactly hapens when
erase is called? The documentation i found on microsft does not seem
to explain this.

You're right. std::map::erase doesn't return anything, probably because
the tree gets re-sorted/rebalanced after deleting, and iterator ordering
may no longer make sense.

If you're just ripping through in order, you might want to try:

while (!phoneBook.empty())
{
i = phoneBook.begin();
// do stuff with i
phoneBook.erase(i);
}

Or, alternatively

std::for_each(phoneBook.begin(),
phoneBook.end(),
DoSomethingWithPhoneBookFunctor());
phoneBook.clear();
 
K

Kelly Mandrake

Well that worked, and It never ocured to me to test for empty. So
every time i call erase the tree is resorted, very interesting. Still
trying to figure out things I looked up the documentation for end and i
was suprized, one reference mentioned that if the map is empty then
end() is the same as begin(), but when I tested for begin I got same
results. But it makes sence now you mention the tree gets resorted, so
end gets confused.

Both your examples worked thank you for these. I decided to try one on
my own after reviewing yours and came up with

for (hashTable::iterator i = phoneBook.begin(); !phoneBook.empty();
i++)
{
cout << i->first << endl;
phoneBook.erase(i);
}
 
R

red floyd

Kelly said:
Well that worked, and It never ocured to me to test for empty. So
every time i call erase the tree is resorted, very interesting. Still
trying to figure out things I looked up the documentation for end and i
was suprized, one reference mentioned that if the map is empty then
end() is the same as begin(), but when I tested for begin I got same
results. But it makes sence now you mention the tree gets resorted, so
end gets confused.

Both your examples worked thank you for these. I decided to try one on
my own after reviewing yours and came up with

for (hashTable::iterator i = phoneBook.begin(); !phoneBook.empty();
i++)
{
cout << i->first << endl;
phoneBook.erase(i);
}

Still not good. After the phoneBook.erase(i) statement, i is not longer
a valid iterator, and the i++ in the loop is UB.

Also, when dealing with iterators, it's generally considered better form
to use the preincrement (++i) form unless there's a really good reason
for postincrement.
 
K

Kelly Mandrake

It did compile and execute ok for me though, all three seem to work.
May I ask which STL you are useing, I am useing g++ 3.4 with stl that
came with it. I will remember to use the preincrement from now on,
thanks for this.
 
M

msalters

red said:
At this point, i is an invalid iterator. I suspect the correct code
should be:

for (i = phoneBook.begin(); i != phoneBook.end() ; )
{
cout << i->first.endl;
i = phoneBook.erase(i); // guess, don't know what
// hashmap::erase returns
}

Basic idea is OK, but this depends on the return type of erase.
This is one of the few cases where post-increment
is useful (++i is at least as efficient and often more)

for (i = phoneBook.begin(); i != phoneBook.end() ; )
{
cout << i->first.endl;
phoneBook.erase(i++);
}
the point is that i++ returns the old value as a temporary. Usually
that's totally redundant, but in this case it's very useful. Once
erased, the temporary iterator is destroyed.

This will also work if empty, because an empty container has
begin==end (another reason why STL uses half-open ranges).

(Note: hashmap is not a std:: class yet, so what you've got may
in fact invalidate all iterators on an erase. So, RTFM )

HTH,
Michiel Salters
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,201
Messages
2,571,051
Members
47,656
Latest member
rickwatson

Latest Threads

Top