STL NewbieQ: Remove entry from multimap and keep scanning

J

John Mills

Hello -

I'm using STL's 'multimap' type and wish to remove multimap entries for
which 'second' matches some test, roughly as follows:

multimap<type1, type2> mm;
multimap<type1, type2>::iterator pos;
...
for(pos = mm.begin(); pos != mm.end(); ++pos)
if (mytest(pos->second)) {
mm.erase(pos);
break;
}
...

This _should_ work because I expect only one matching map entry at any one
time, but I wondered how to keep looking for more matches, _after_ having
erased the element at 'pos'. Is the iterator still useful after my
'erase'? (My reference says the multimap 'erase' is of type 'void', unlike
[say] for a vector.)

TIA from a Newbie.

- John Mills
(e-mail address removed)
 
J

John Harrison

John Mills said:
Hello -

I'm using STL's 'multimap' type and wish to remove multimap entries for
which 'second' matches some test, roughly as follows:

multimap<type1, type2> mm;
multimap<type1, type2>::iterator pos;
...
for(pos = mm.begin(); pos != mm.end(); ++pos)
if (mytest(pos->second)) {
mm.erase(pos);
break;
}
...

This _should_ work because I expect only one matching map entry at any one
time,
Right.

but I wondered how to keep looking for more matches, _after_ having
erased the element at 'pos'. Is the iterator still useful after my
'erase'?

No, and so calling ++pos after an erase is an error.
(My reference says the multimap 'erase' is of type 'void', unlike
[say] for a vector.)

Simple, increment pos before you call erase, not afterwards. The simplest
way is this

for(pos = mm.begin(); pos != mm.end(); )
if (mytest(pos->second)) {
mm.erase(pos++);
} else {
++pos;
}

john
 
P

Pete C.

John said:
Hello -

I'm using STL's 'multimap' type and wish to remove multimap entries
for which 'second' matches some test, roughly as follows:

multimap<type1, type2> mm;
multimap<type1, type2>::iterator pos;
...
for(pos = mm.begin(); pos != mm.end(); ++pos)
if (mytest(pos->second)) {
mm.erase(pos);
break;
}
...

This _should_ work because I expect only one matching map entry at
any one time, but I wondered how to keep looking for more matches,
_after_ having erased the element at 'pos'. Is the iterator still
useful after my 'erase'? (My reference says the multimap 'erase' is
of type 'void', unlike [say] for a vector.)

TIA from a Newbie.

- John Mills
(e-mail address removed)

Try std::remove_if:

struct ShouldRemove
{
int something;
ShouldRemove(int n) : something(n) {}
bool operator() (std::pair<int, int>& p)
{
if(p.second == something)
return true;
else
return false;
}
};

// remove all items where second is 123
mm.erase(std::remove_if(mm.begin(), mm.end(), ShouldRemove(123)), mm.end());

- Pete
 
J

Julie

John said:
No, and so calling ++pos after an erase is an error.

Simple, increment pos before you call erase, not afterwards. The simplest
way is this

for(pos = mm.begin(); pos != mm.end(); )
if (mytest(pos->second)) {
mm.erase(pos++);
} else {
++pos;
}

john

Isn't:

mm.erase(pos++);

and

mm.erase(pos);
++pos;

the same?
 
J

John Harrison

Julie said:
Isn't:

mm.erase(pos++);

and

mm.erase(pos);
++pos;

the same?

Not at all. In the first case pos is incremented before erase is called (but
the old value of pos is passed to erase). In the second pos is incremented
after the call to erase.

This often confuses, but it is the case that arguments to a function must be
evaluated before the function is called, that applies to the post increment
operator just as much as anything else.

john
 
P

P.J. Plauger

Try std::remove_if:

struct ShouldRemove
{
int something;
ShouldRemove(int n) : something(n) {}
bool operator() (std::pair<int, int>& p)
{
if(p.second == something)
return true;
else
return false;
}
};

// remove all items where second is 123
mm.erase(std::remove_if(mm.begin(), mm.end(), ShouldRemove(123)),
mm.end());

Nope. remove_if copies the surviving members down in a sequence.
You can't do that inside a multimap.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
M

Mats Weber

John Harrison said:
Simple, increment pos before you call erase, not afterwards. The simplest
way is this

for(pos = mm.begin(); pos != mm.end(); )
if (mytest(pos->second)) {
mm.erase(pos++);

I think you need
break;
here if you want your code to do the same as the OP's.
 
J

John Harrison

Mats Weber said:
I think you need
break;
here if you want your code to do the same as the OP's.

No, the whole point of my post was to explain to the OP how to handle the
case where he wanted to remove more than one item from his map.

john
 

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top