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
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;
}
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.
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).
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.
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() )
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)