STL NewbieQ: Remove entry from multimap and keep scanning

Discussion in 'C++' started by John Mills, Jun 22, 2004.

  1. John Mills

    John Mills Guest

    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
     
    John Mills, Jun 22, 2004
    #1
    1. Advertising

  2. "John Mills" <> wrote in message
    news:p...
    > 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
     
    John Harrison, Jun 22, 2004
    #2
    1. Advertising

  3. John Mills

    Pete C. Guest

    John Mills wrote:
    > 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
    >


    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
     
    Pete C., Jun 22, 2004
    #3
  4. John Mills

    Julie Guest

    John Harrison wrote:
    > 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?
     
    Julie, Jun 22, 2004
    #4
  5. "Julie" <> wrote in message
    news:...
    > John Harrison wrote:
    > > 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?


    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
     
    John Harrison, Jun 22, 2004
    #5
  6. John Mills

    P.J. Plauger Guest

    "Pete C." <> wrote in message
    news:rr1Cc.14437$...

    > 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
     
    P.J. Plauger, Jun 23, 2004
    #6
  7. John Mills

    Mats Weber Guest

    In article <>,
    "John Harrison" <> wrote:

    >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.

    > } else {
    > ++pos;
    > }
     
    Mats Weber, Jun 23, 2004
    #7
  8. "Mats Weber" <> wrote in message
    news:...
    > In article <>,
    > "John Harrison" <> wrote:
    >
    > >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.
    >


    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
     
    John Harrison, Jun 23, 2004
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Simon-Pierre  Jarry
    Replies:
    2
    Views:
    2,414
    Henrik
    Aug 10, 2005
  2. Replies:
    4
    Views:
    549
  3. Tommo
    Replies:
    2
    Views:
    599
    Tom Widmer
    May 22, 2006
  4. Anon

    multimap stl

    Anon, Dec 21, 2006, in forum: C++
    Replies:
    3
    Views:
    521
    Mark P
    Dec 21, 2006
  5. reppisch
    Replies:
    6
    Views:
    1,025
    reppisch
    Jun 19, 2007
Loading...

Share This Page