Search code examples
c++stliterator

Testing whether an iterator points to the last item?


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 = someValue;
vector<mine *> Mine(someContent);
vector<mine *>::iterator itr = std::find(Mine.begin(), Mine.end(), match);

if (itr == --Mine.end()) {
  doSomething;
}

But it seems to me that decrementing the end() iterator is asking for trouble, such as if the vector has no elements, then it would be undefined. Even if I know it will never be empty, it still seems ugly. I'm thinking that maybe rbegin() is the way to go, but am not certain as to best way to compare the forward iterator with a reverse iterator.


Solution

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