unexpected result using std::list

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Mike Pemberton

    unexpected result using std::list

    I'm sure there's a good explanation for this effect, but I get rather
    a strange output from this little test:

    #include <iostream>
    #include <list>

    int main()
    {
    std::list<int> int_list;

    int_list.push_b ack(1);
    int_list.push_b ack(2);
    int_list.push_b ack(3);
    int_list.push_b ack(4);

    std::list<int>: :reverse_iterat or rev = int_list.rbegin ();
    while(rev != int_list.rend() )
    {
    std::cout << *rev++ << std::endl;
    int_list.pop_ba ck(); // This line causes a problem.
    }
    return 0;
    }

    Output:
    4
    3
    2
    1
    0
    0

    The inclusion of the int_list.pop_ba ck() call seems to cause the two
    additional iterations through the loop that print the two extra zeros.
    If I comment out the int_list.pop_ba ck() line the output is as
    expected, and if i use a different conditional statement such as
    while(! int_list.empty( )) the output is also as expected.

    Does anyone know why this doesn't work? Are there member functions of
    std::list that shouldn't be used with iterators, reverse-iterators or
    something?

    I'm using Red Hat 7 & g++.
  • tom_usenet

    #2
    Re: unexpected result using std::list

    On 14 Oct 2003 07:20:15 -0700, mhpemberton@vod afone.net (Mike
    Pemberton) wrote:
    [color=blue]
    >I'm sure there's a good explanation for this effect, but I get rather
    >a strange output from this little test:
    >
    >#include <iostream>
    >#include <list>
    >
    >int main()
    >{
    > std::list<int> int_list;
    >
    > int_list.push_b ack(1);
    > int_list.push_b ack(2);
    > int_list.push_b ack(3);
    > int_list.push_b ack(4);
    >
    > std::list<int>: :reverse_iterat or rev = int_list.rbegin ();
    > while(rev != int_list.rend() )
    > {
    > std::cout << *rev++ << std::endl;
    > int_list.pop_ba ck(); // This line causes a problem.[/color]

    The above line erases the element that rev is pointing to! Remember
    that a reverse iterator's base iterator is actually the iterator to
    the element after the one that dereferences. In any case, the above
    line invalidates rev, so you can't legally perform any operations on
    it, including comparing it to rend, dereferencing it and incrementing
    it.
    [color=blue]
    > }
    > return 0;
    >}
    >
    >Output:
    >4
    >3
    >2
    >1
    >0
    >0
    >
    >The inclusion of the int_list.pop_ba ck() call seems to cause the two
    >additional iterations through the loop that print the two extra zeros.
    > If I comment out the int_list.pop_ba ck() line the output is as
    >expected, and if i use a different conditional statement such as
    >while(! int_list.empty( )) the output is also as expected.
    >
    >Does anyone know why this doesn't work? Are there member functions of
    >std::list that shouldn't be used with iterators, reverse-iterators or
    >something?[/color]

    Yes, any list operation that erases an element invalidates all
    iterators to that element. A reverse iterator is a strange beast,
    since its base iterator is actually the one after the element it
    dereferences to.

    Tom

    Comment

    • Victor Bazarov

      #3
      Re: unexpected result using std::list

      "Mike Pemberton" <mhpemberton@vo dafone.net> wrote...[color=blue]
      > I'm sure there's a good explanation for this effect, but I get rather
      > a strange output from this little test:
      >
      > #include <iostream>
      > #include <list>
      >
      > int main()
      > {
      > std::list<int> int_list;
      >
      > int_list.push_b ack(1);
      > int_list.push_b ack(2);
      > int_list.push_b ack(3);
      > int_list.push_b ack(4);
      >
      > std::list<int>: :reverse_iterat or rev = int_list.rbegin ();
      > while(rev != int_list.rend() )
      > {
      > std::cout << *rev++ << std::endl;
      > int_list.pop_ba ck(); // This line causes a problem.
      > }
      > return 0;
      > }
      >
      > Output:
      > 4
      > 3
      > 2
      > 1
      > 0
      > 0
      >
      > The inclusion of the int_list.pop_ba ck() call seems to cause the two
      > additional iterations through the loop that print the two extra zeros.
      > If I comment out the int_list.pop_ba ck() line the output is as
      > expected, and if i use a different conditional statement such as
      > while(! int_list.empty( )) the output is also as expected.
      >
      > Does anyone know why this doesn't work? Are there member functions of
      > std::list that shouldn't be used with iterators, reverse-iterators or
      > something?[/color]

      Not sure off the top of my head, but at the time when you pop_back
      the "last" element (at the moment when the list becomes empty), the
      'rev' iterator may actually become screwed up.

      Although the 'pop_back' is said to invalidate only the iterators and
      references to the erased elements, the problem is that when pop_back
      empties the list, iterators that used to be the same as the ends of
      the list may become not the same any more, I think that's what you
      are experiencing here.

      For more clarification ask about it in comp.std.c++. FWIW, it could
      be a defect in the Standard (the fact that it doesn't specify what
      happens to the iterator which _is_ supposedly pointing 'one past the
      end'.

      Try this:
      ------------------------------------------------------------------
      #include <string>
      #include <iostream>
      #include <list>
      using namespace std;

      int main()
      {
      list<int> int_list;

      list<int>::reve rse_iterator rev = int_list.rbegin ();

      cout << "'rev' is " << (rev == int_list.rend() ? "" : "NOT ")
      << "the same as 'rend()'\n";

      cout << "Pushing '1'...\n";

      int_list.push_b ack(1);

      cout << "Resetting 'rev'...\n";

      rev = int_list.rbegin ();

      cout << "'rev' is " << (rev == int_list.rend() ? "" : "NOT ")
      << "the same as 'rend()'\n";

      cout << "'rev' points to " << *rev++ << std::endl;

      cout << "After ++ ";

      cout << "'rev' is " << (rev == int_list.rend() ? "" : "NOT ")
      << "the same as 'rend()'\n";

      cout << "Popping the back\n";
      int_list.pop_ba ck(); // This line causes a problem.

      cout << "'rev' is " << (rev == int_list.rend() ? "" : "NOT ")
      << "the same as 'rend()'\n";

      string s;
      getline(cin, s);
      }

      ------------------------------------------------------------------

      Victor



      Comment

      • Dan Cernat

        #4
        Re: unexpected result using std::list

        mhpemberton@vod afone.net (Mike Pemberton) wrote in message news:<bcd9b584. 0310140620.13ba f810@posting.go ogle.com>...[color=blue]
        > I'm sure there's a good explanation for this effect, but I get rather
        > a strange output from this little test:
        >
        > #include <iostream>
        > #include <list>
        >
        > int main()
        > {
        > std::list<int> int_list;
        >
        > int_list.push_b ack(1);
        > int_list.push_b ack(2);
        > int_list.push_b ack(3);
        > int_list.push_b ack(4);
        >
        > std::list<int>: :reverse_iterat or rev = int_list.rbegin ();
        > while(rev != int_list.rend() )
        > {
        > std::cout << *rev++ << std::endl;
        > int_list.pop_ba ck(); // This line causes a problem.
        > }
        > return 0;
        > }
        >
        > Output:
        > 4
        > 3
        > 2
        > 1
        > 0
        > 0
        >
        > The inclusion of the int_list.pop_ba ck() call seems to cause the two
        > additional iterations through the loop that print the two extra zeros.
        > If I comment out the int_list.pop_ba ck() line the output is as
        > expected, and if i use a different conditional statement such as
        > while(! int_list.empty( )) the output is also as expected.
        >
        > Does anyone know why this doesn't work? Are there member functions of
        > std::list that shouldn't be used with iterators, reverse-iterators or
        > something?
        >
        > I'm using Red Hat 7 & g++.[/color]

        pop_back invalidates the iterator. Generally, insertions and deletions
        invalidate iterators. I think this is what happens.

        Comment

        Working...