set<>::erase(iterator) question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Harald Grossauer

    set<>::erase(iterator) question

    Usually STL containers have something like "iterator
    container<>::er ase(iterator)" which erases the element the iterator points
    to and returns another valid iterator. Set does not have this, set::erase()
    returns void and "invalidate s" the iterator.

    Now I have the following code:

    while(!some_set .empty()) {
    for(it = some_set.begin( ); it != some_set.end(); it++)
    {
    ...
    if (something == true) some_set.erase( it);
    ...
    }
    }

    And it always worked (using GCC3.2). Now running the same program using the
    same test data on another machine (GCC3.3) it is caught in an endless loop.
    What could be going on here?

  • WW

    #2
    Re: set&lt;&gt;::er ase(iterator) question

    Harald Grossauer wrote:[color=blue]
    > Usually STL containers have something like "iterator
    > container<>::er ase(iterator)" which erases the element the iterator
    > points to and returns another valid iterator. Set does not have this,
    > set::erase() returns void and "invalidate s" the iterator.[/color]
    [SNIP]

    Get Effective STL from Scott Meyers.

    // This is not necessary: while(!some_set .empty()) {
    for(it = some_set.begin( ); it != some_set.end(); ) // Change
    {
    ...
    if (something == true) some_set.erase( it++); // Change
    else ++it; // Change
    ...
    }

    You need to get the valid iterator *before* the erase runs.

    --
    WW aka Attila


    Comment

    • Ron Natalie

      #3
      Re: set&lt;&gt;::er ase(iterator) question


      "Harald Grossauer" <harald.grossau er@uibk.ac.at> wrote in message news:3f706fb1@s ia.uibk.ac.at.. .[color=blue]
      > Usually STL containers have something like "iterator
      > container<>::er ase(iterator)" which erases the element the iterator points
      > to and returns another valid iterator.[/color]

      That's true for sequences.
      [color=blue]
      > Set does not have this, set::erase() returns void and "invalidate s" the iterator.[/color]

      That's the way associative containers are, unfortuantely. However, the nice thing
      is that they only invalidate the erased iterator.
      [color=blue]
      > for(it = some_set.begin( ); it != some_set.end(); it++)
      > {
      > ...
      > if (something == true) some_set.erase( it);
      > ...
      > }[/color]
      You have two chocies:
      1. remember the next iterator somewhere
      2. use post increment to accomplish the same thing

      next_it = it+1;
      if(something == true) some_set.erase( it);
      it = next_it;

      or
      if(something == true) some_set.erase( it++);
      else ++it;


      Comment

      • keanu

        #4
        Re: set&lt;&gt;::er ase(iterator) question

        WW wrote in <bkprlo$fg3$1@p hys-news1.kolumbus. fi>:
        [color=blue]
        > Harald Grossauer wrote:[color=green]
        >> Usually STL containers have something like "iterator
        >> container<>::er ase(iterator)" which erases the element the iterator
        >> points to and returns another valid iterator. Set does not have this,
        >> set::erase() returns void and "invalidate s" the iterator.[/color]
        > [SNIP]
        >
        > Get Effective STL from Scott Meyers.
        >
        > // This is not necessary: while(!some_set .empty()) {
        > for(it = some_set.begin( ); it != some_set.end(); ) // Change
        > {
        > ...
        > if (something == true) some_set.erase( it++); // Change
        > else ++it; // Change
        > ...
        > }
        >
        > You need to get the valid iterator *before* the erase runs.[/color]

        if i'm not mistaken erase returns the next valid iterator, so:
        [color=blue]
        > for(it = some_set.begin( ); it != some_set.end(); ) // Change
        > {
        > ...[/color]
        if (something == true)
        it = some_set.erase( it++);
        ...[color=blue]
        > }[/color]

        should do the trick?

        --
        Groeten keanu,
        Jabber ID: knu[at]amessage[dot]de
        GPG Key-ID: 0x3246DE81

        Comment

        • Ron Natalie

          #5
          Re: set&lt;&gt;::er ase(iterator) question


          "keanu" <usenet@keanu.b e> wrote in message news:H00cb.3620 4$_q1.1687695@p hobos.telenet-ops.be...
          [color=blue]
          > if i'm not mistaken erase returns the next valid iterator, so:[/color]

          Yoiu are mistaken. Did you even read the original post? The erase on
          associative containers do not, unfortunately, return anything.
          [color=blue]
          >[color=green]
          > > for(it = some_set.begin( ); it != some_set.end(); ) // Change
          > > {
          > > ...[/color]
          > if (something == true)
          > it = some_set.erase( it++);
          > ...[color=green]
          > > }[/color][/color]

          That won't even work on containers where erase DOES return something. It's
          undefined behavior in that case. You can do on sequences

          if(something)
          it = some_sequence.e rase(it);
          else ++it;

          or on associative containers
          if(something)
          some_set(it++);
          else ++it;


          Comment

          • Kevin Goodsell

            #6
            Re: set&lt;&gt;::er ase(iterator) question

            keanu wrote:
            [color=blue]
            >
            > if i'm not mistaken erase returns the next valid iterator, so:[/color]

            Not for associative containers. That's sort of the point of the thread.

            -Kevin
            --
            My email address is valid, but changes periodically.
            To contact me please use the address from a recent posting.

            Comment

            • Kevin Goodsell

              #7
              Re: set&lt;&gt;::er ase(iterator) question

              Ron Natalie wrote:
              [color=blue]
              >[color=green][color=darkred]
              >>>for(it = some_set.begin( ); it != some_set.end(); ) // Change
              >>>{
              >>> ...[/color]
              >>
              >> if (something == true)
              >> it = some_set.erase( it++);
              >> ...
              >>[color=darkred]
              >>>}[/color][/color]
              >
              >
              > That won't even work on containers where erase DOES return something. It's
              > undefined behavior in that case.[/color]

              Why is it undefined behavior? The increment is 'finished' before the
              function call (sequence point immediately before a function call) and
              the assignment occurs after, right?

              -Kevin
              --
              My email address is valid, but changes periodically.
              To contact me please use the address from a recent posting.

              Comment

              • keanu

                #8
                Re: set&lt;&gt;::er ase(iterator) question

                > That won't even work on containers where erase DOES return something.[color=blue]
                > It's
                > undefined behavior in that case. You can do on sequences
                >
                > if(something)
                > it = some_sequence.e rase(it);
                > else ++it;[/color]

                this is what i meant, the ++ was a left over from the copy paste + no sleep

                for some reason i thought erase returns the next iterator for every
                container

                Comment

                • Ron Natalie

                  #9
                  Re: set&lt;&gt;::er ase(iterator) question


                  "Kevin Goodsell" <usenet1.spamfr ee.fusion@never box.com> wrote in message news:MI0cb.858$ RW4.72@newsread 4.news.pas.eart hlink.net...
                  [color=blue][color=green][color=darkred]
                  > >> it = some_set.erase( it++);[/color][/color][/color]
                  [color=blue]
                  >
                  > Why is it undefined behavior? The increment is 'finished' before the
                  > function call (sequence point immediately before a function call) and
                  > the assignment occurs after, right?[/color]

                  Yeah, I guess you're right. I was thinking that the side effect could be delayed
                  but there is an inherent sequence point after the function args are evaluated and
                  again on return.


                  Comment

                  • Harald Grossauer

                    #10
                    Re: set&lt;&gt;::er ase(iterator) question

                    Ron Natalie wrote:

                    [color=blue]
                    > You have two chocies:
                    > 1. remember the next iterator somewhere
                    > 2. use post increment to accomplish the same thing
                    >
                    > next_it = it+1;
                    > if(something == true) some_set.erase( it);
                    > it = next_it;[/color]

                    That's how I did it then. I just thought there might be a "nicer" version
                    without introducing another "dummy iterator".
                    [color=blue]
                    >
                    > or
                    > if(something == true) some_set.erase( it++);
                    > else ++it;[/color]

                    Comment

                    Working...