Iterator questions...

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

    Iterator questions...

    I've noticed that neither container.begin () nor container.end() return
    an error when the container is empty, so I get a nasty segfault when I
    dereference the iterator. Do I have to check if the container is
    empty every time I use an iterator, or am I missing something?

    Speaking of iterators: if I initialize 'iter = container.end() ', can I
    count on iter to stay equal to container.end() even if elements are
    deleted and added to the container?
  • Kai-Uwe Bux

    #2
    Re: Iterator questions...

    barcaroller wrote:
    I've noticed that neither container.begin () nor container.end() return
    an error when the container is empty,
    Why should they? Empty ranges are perfectly valid and std::sort() will
    happily sort an empty range.
    so I get a nasty segfault when I dereference the iterator.
    Dereferencing an invalid iterator is undefined behavior. You got lucky that
    your platform did the right thing and alerted you of the bug.
    Do I have to check if the container is
    empty every time I use an iterator,
    You have to ensure that the iterator is valid before you dereference it. If
    you don't know whether the container is empty, you will have to check.
    or am I missing something?
    No, you seem to be spot on.

    Speaking of iterators: if I initialize 'iter = container.end() ', can I
    count on iter to stay equal to container.end() even if elements are
    deleted and added to the container?
    That depends on the container: if I recall correctly, only std::list and the
    associative containers make that kind of guarantee.


    Best

    Kai-Uwe Bux

    Comment

    • Jim Langston

      #3
      Re: Iterator questions...

      barcaroller wrote:
      I've noticed that neither container.begin () nor container.end() return
      an error when the container is empty, so I get a nasty segfault when I
      dereference the iterator. Do I have to check if the container is
      empty every time I use an iterator, or am I missing something?
      You are missing something. For an empty containter .begin() == .end()

      Aren't you checking to make sure your iteratores aren't equal to .end()?

      One of the most common uses of .begin() and .end() is in a for loop, such
      as:

      std::list<intDa ta;
      for ( std::list<int>: :iterator it = Data.begin(); it != Data.end(); ++it )
      {
      // it is guaranteed to be pointing to an item in the list
      }

      Other uses include passing them to algorithms, also as result of .find()
      etc..

      But in all cases you must ensure that your iterator != .end()
      Speaking of iterators: if I initialize 'iter = container.end() ', can I
      count on iter to stay equal to container.end() even if elements are
      deleted and added to the container?
      Hmm.. I'm not sure. I do know that some operations on containers can
      invalidate iterators. I'm fairly sure that this includes .end() which
      points one past the last item in the container.

      --
      Jim Langston
      tazmaster@rocke tmail.com


      Comment

      • Pascal J. Bourguignon

        #4
        Re: Iterator questions...

        "Jim Langston" <tazmaster@rock etmail.comwrite s:
        barcaroller wrote:
        >I've noticed that neither container.begin () nor container.end() return
        >an error when the container is empty, so I get a nasty segfault when I
        >dereference the iterator. Do I have to check if the container is
        >empty every time I use an iterator, or am I missing something?
        >
        You are missing something. For an empty containter .begin() == .end()
        Even more, .end() is always an invalid iterator that cannot be
        derefenced!
        [...]
        But in all cases you must ensure that your iterator != .end()
        >
        >Speaking of iterators: if I initialize 'iter = container.end() ', can I
        >count on iter to stay equal to container.end() even if elements are
        >deleted and added to the container?
        >
        Hmm.. I'm not sure. I do know that some operations on containers can
        invalidate iterators. I'm fairly sure that this includes .end() which
        points one past the last item in the container.
        Yes, the old value of .end() may become valid, which would be invalid,
        for an iterator that must always be invalid :-)

        --
        __Pascal Bourguignon__

        Comment

        • Juha Nieminen

          #5
          Re: Iterator questions...

          barcaroller wrote:
          I've noticed that neither container.begin () nor container.end() return
          an error when the container is empty, so I get a nasty segfault when I
          dereference the iterator. Do I have to check if the container is
          empty every time I use an iterator, or am I missing something?
          What do you suggest would happen if you dereference the begin()
          iterator of an empty container?

          You have to check if the iterator equals the end() iterator before
          dereferencing it. Dereferencing the end() iterator is invalid.

          Comment

          • barcaroller

            #6
            Re: Iterator questions...

            On May 15, 11:54 pm, "Jim Langston" <tazmas...@rock etmail.comwrote :

            One of the most common uses of .begin() and .end() is in a for loop, such
            as:
            >
            std::list<intDa ta;
            for ( std::list<int>: :iterator it = Data.begin(); it != Data.end(); ++it )
            {
            // it is guaranteed to be pointing to an item in the list
            >
            }

            Actually, I'm not using the iterator in a loop. Briefly, I save the
            iterator of the last successful find(). Before I call find() again, I
            first check if the last iterator points to the info that I need. If
            not, then I
            call find(). In essence, I'm caching the iterator to improve
            performance, by avoiding a call to find().

            Note: where find() is either a member function or an algorithm.

            However, caching iterators has its own problems. Initialization,
            invalidation, etc.

            Comment

            • barcaroller

              #7
              Re: Iterator questions...

              On May 16, 4:11 am, Juha Nieminen <nos...@thanks. invalidwrote:
              What do you suggest would happen if you dereference the begin()
              iterator of an empty container?
              As I said earlier, I get a segfault. I would expect begin() to return
              the iterator equivalent of NULL or throw an exception or something.
              If the container is empty, begin() should not return a valid value.
              But that's just my opinion.

              You have to check if the iterator equals the end() iterator before
              dereferencing it. Dereferencing the end() iterator is invalid.
              Yes, that's right. Please see my response to Jim.

              Comment

              • Jim Langston

                #8
                Re: Iterator questions...

                barcaroller wrote:
                On May 15, 11:54 pm, "Jim Langston" <tazmas...@rock etmail.comwrote :
                >
                >
                >One of the most common uses of .begin() and .end() is in a for loop,
                >such as:
                >>
                >std::list<intD ata;
                >for ( std::list<int>: :iterator it = Data.begin(); it != Data.end();
                >++it ) {
                > // it is guaranteed to be pointing to an item in the list
                >>
                >}
                >
                >
                Actually, I'm not using the iterator in a loop. Briefly, I save the
                iterator of the last successful find(). Before I call find() again, I
                first check if the last iterator points to the info that I need. If
                not, then I
                call find(). In essence, I'm caching the iterator to improve
                performance, by avoiding a call to find().
                >
                Note: where find() is either a member function or an algorithm.
                >
                However, caching iterators has its own problems. Initialization,
                invalidation, etc.
                ..find() can and will return .end() if the item was not found. You need to
                test for this and not attempt to dereference the iterator if it is .end().
                Also be aware that you are "saving the iterator". Be sure there is no
                interventing changes to the vector that can invalidate your reference.
                Without seeing your actual code I can not say for certain why the
                dereference is not working, only that there is something you are not taking
                into account, most likely the iterator pointing to .end() or being
                invalidated because of operations on the container.

                --
                Jim Langston
                tazmaster@rocke tmail.com


                Comment

                • Jim Langston

                  #9
                  Re: Iterator questions...

                  barcaroller wrote:
                  On May 16, 4:11 am, Juha Nieminen <nos...@thanks. invalidwrote:
                  >
                  > What do you suggest would happen if you dereference the begin()
                  >iterator of an empty container?
                  >
                  As I said earlier, I get a segfault. I would expect begin() to return
                  the iterator equivalent of NULL or throw an exception or something.
                  If the container is empty, begin() should not return a valid value.
                  But that's just my opinion.
                  If the container is empty .begin() will be equal to .end() which is invalid
                  to be referenced but can be tested against.

                  In a way, .end() is the iterator equivalent of NULL, as both can not be
                  dereference and both can be tested against.
                  > You have to check if the iterator equals the end() iterator before
                  >dereferencin g it. Dereferencing the end() iterator is invalid.
                  >
                  Yes, that's right. Please see my response to Jim.


                  --
                  Jim Langston
                  tazmaster@rocke tmail.com


                  Comment

                  • barcaroller

                    #10
                    Re: Iterator questions...


                    "Jim Langston" <tazmaster@rock etmail.comwrote in message
                    news:NA7Xj.172$ J43.23@newsfe05 .lga...
                    barcaroller wrote:
                    >I've noticed that neither container.begin () nor container.end() return
                    >an error when the container is empty, so I get a nasty segfault when I
                    >dereference the iterator. Do I have to check if the container is
                    >empty every time I use an iterator, or am I missing something?
                    >
                    You are missing something. For an empty containter .begin() == .end()
                    >
                    Aren't you checking to make sure your iteratores aren't equal to .end()?
                    >
                    One of the most common uses of .begin() and .end() is in a for loop, such
                    as:
                    >
                    std::list<intDa ta;
                    for ( std::list<int>: :iterator it = Data.begin(); it != Data.end(); ++it )
                    {
                    // it is guaranteed to be pointing to an item in the list
                    }
                    >
                    Actually, I'm not using the iterator in a loop. Briefly, I save the
                    iterator of the last successful find(). Before I call find() again, I first
                    check if the last iterator points to the info that I need. If not, then I
                    call find(). In essence, I'm caching the iterator to improve performance,
                    by avoiding a call to find().

                    Note: where find() is either a member function or an algorithm.

                    However, caching iterators has its own problems. Initialization,
                    invalidation, etc.


                    Comment

                    • barcaroller

                      #11
                      Re: Iterator questions...

                      On May 16, 8:10 pm, "Jim Langston" <tazmas...@rock etmail.comwrote :
                      barcaroller wrote:
                      In a way, .end() is the iterator equivalent of NULL, as both can not be
                      dereference and both can be tested against.
                      Indeed, with one exception. Unlike NULL, the value of end() can
                      change for some containers, making the following code invalid:

                      // Initialize savedlastIter
                      savedlastIter = container.end() ;

                      // Lots of other code

                      if (savedLastIter == container.end() )
                      {
                      // savedLastIter has not been set yet
                      savedlastIter = container.find( whatIWant);

                      // could still be end()
                      }
                      else
                      {
                      // savedlastIter seems to have been set
                      if (savedlastIter->whatIwant())
                      // we're done
                      else
                      {
                      savedLastIter= find(whatIWant) ;

                      // could still be end()
                      }
                      }


                      This is just pseudo-code; there's lost of safety checks missing but
                      you get the idea.

                      Comment

                      • barcaroller

                        #12
                        Re: Iterator questions...

                        On May 15, 7:44 pm, barcaroller <barcarol...@gm ail.comwrote:
                        I've noticed that neither container.begin () nor container.end() return
                        an error when the container is empty, so I get a nasty segfault when I
                        dereference the iterator. Do I have to check if the container is
                        empty every time I use an iterator, or am I missing something?
                        >
                        Speaking of iterators: if I initialize 'iter = container.end() ', can I
                        count on iter to stay equal to container.end() even if elements are
                        deleted and added to the container?
                        I apologize for the duplicate messages in this thread. I don't know
                        why the server is doing this.

                        Comment

                        Working...