Testing whether an iterator points to the last item?

前端 未结 9 894
旧巷少年郎
旧巷少年郎 2020-12-23 11:31

I have an stl iterator resulting from a std::find() and wish to test whether it is the last element. One way to write this is as follows:

mine *match = some         


        
相关标签:
9条回答
  • 2020-12-23 12:14

    Why do you need to do special behavior only if the item is the last one?

    What about this. The plan is just to compare the address of the iterator's item with the address of the last item in the container, with a check to make sure the item is actually not already the end (making the back call safe):

    if (itr != Mine.end() && &*itr == &Mine.back()) {
      doSomething;
    }
    
    0 讨论(0)
  • 2020-12-23 12:14

    Trying to make this answer as simple and versatile as possible:

    if( itr!=Mine.end() && itr== --Mine.end())
    

    If the iterator is not bi-directional,

    if( itr!=Min.end() && ++decltype(itr)(itr)==Mine.end())
    

    The second create a temporal copy of itr and increment it to test against the end iterator.

    In both cases, the first test avoid empty containers to trigger an undefined situation.

    0 讨论(0)
  • 2020-12-23 12:24

    This is essentially the same problem as deleting a node from a singly-linked list. You have to have two iterators, one that follows one node behind the other, so when the "forward" iterator gets to the node you want to delete (or whatever operation; in your case the desired node would be the end), the "following" iterator is pointing to the node before (in your case, this would be the final node).

    0 讨论(0)
  • 2020-12-23 12:25

    Do this:

    // defined in boost/utility.hpp, by the way
    template <typename Iter>
    Iter next(Iter iter)
    {
        return ++iter;
    }
    
    // first check we aren't going to kill ourselves
    // then check if the iterator after itr is the end
    if ((itr != Mine.end()) && (next(itr) == Mine.end()))
    {
        // points at the last element
    }
    

    That is all. Never gives you undefined behavior, works on all iterators, good day.

    Wrap it up for fun:

    template <typename Iter, typename Cont>
    bool is_last(Iter iter, const Cont& cont)
    {
        return (iter != cont.end()) && (next(iter) == cont.end())
    }
    

    Giving:

    if (is_last(itr, Mine))
    

    If you're allergic to utility functions/nice looking code, do:

    if ((itr != Mine.end()) && (itr + 1 == Mine.end()))
    

    But you can't do it on non-random-access iterators. This one works with bidirectional iterators:

    if ((itr != Mine.end()) && (itr == --Mine.end()))
    

    And is safe since end() > itr by the first check.

    0 讨论(0)
  • 2020-12-23 12:25

    Yes, it's unsafe to decrement (or increment) end if the vector may be empty. It's even somewhat unsafe to do the same with a pointer, although you'll probably get away with it.

    To be really safe, use subtraction and values known to be safe and valid:

    if ( Mine.end() - itr == 1 )
    

    For compatibility with all forward iterators (such as in slist, as opposed to random-access iterators of vector and deque), use

    if ( std::distance( itr, Mine.end() ) == 1 )
    

    or if you are concerned with performance but have bidirectional iterators (incl. any C++03 container)

    if ( itr != Mine.end() && itr == -- Mine.end() )
    

    or the truly anal case of only forward iterators and O(1) time,

    if ( itr != Mine.end() && ++ container::iterator( itr ) == Mine.end() )
    

    or if you are hellbent on cleverness to avoid naming the iterator class,

    if ( itr != Mine.end() && ++ ( Mine.begin() = itr ) == Mine.end() )
    
    0 讨论(0)
  • 2020-12-23 12:28

    If you do:

    if(itr != Mine.end() && itr == --Mine.end())
    

    It should be fine. Because if itr is not at the end then there must be at least 1 element in the container and so end must yield a value result when decremented.

    But if you still don't like that, there are lots of ways to do something equivalent, as all the other answers show.

    Here's another alternative:

    if(itr != Mine.end() && std::distance(Mine.begin(), itr) == Mine.size()-1)
    
    0 讨论(0)
提交回复
热议问题