tags:

views:

128

answers:

6

is it possible to peek next element in a container which the iterator currently points to without changing the iterator?

For example in std::set,

int myArray[]= {1,2,3,4};
set <int> mySet(myArray, myArray+4);
set <int>::iterator iter = mySet.begin();

//peek the next element in set without changing iterator.

mySet.erase(iter); //erase the element if next element is n+1
+2  A: 
set <int>::iterator iter2 = iter;
++iter2;
int peekedValue = *iter2;
Andrew Shepherd
A: 

You can always make a copy of the iterator and advance the copy:

set <int>::iterator iter = mySet.begin();
set <int>::iterator iterCopy = iter;
iterCopy++;
if (*iterCopy == something)
  mySet.erase(iter);

But beware that iterCopy may no longer be valid once you erase iter.

casablanca
"iterCopy may no longer be valid once you erase iter". It will be for a set, but not for all STL containers. I google "SGI STL set" or whatever when I want a good reference... covers all this.
Tony
Be aware, however, that SGI is a great resource for the STL. It isn't entirely accurate as far as the C++ standard library is concerned, however. The STL contains several non-standard containers/algorithms, and the containers that are part of standard C++ don't match up on some of the details, particularly with regard to allocators.
Dennis Zickefoose
+8  A: 

Not with iterators in general. An iterator isn't guaranteed to be able to operate non-destructively. The classic example is an Input Iterator that actually represents an underlying input stream.

There's something that works for this kind of iterator, though. A Forward Iterator doesn't invalidate previous copies of itself by the act of moving forward through the collection. Most iterators (including those for STL collections) are at least Forward Iterators, if not a more functional version- only Input Iterators or Output Iterators are more restricted. So you can simply make a copy of your iterator, increment the copy and check that, then go back to your original iterator.

So your peek code:

set <int>::iterator dupe = iter;
++dupe;
// (do stuff with dupe)
Kistaro Windrider
A: 

for sequence containers (vector, deque, and list) you can call front which will give you a peek (more info on the lower part of this link).

skimobear
A: 

This will not work for std::set as its nature does not allow for the [] operator, but for containers that do, you can do:

std::vector<int> v;
v.push_back(3);
v.push_back(4);
std::vector<int>::iterator it = v.begin(); 
std::cout << v[it - v.begin() + 1];

But this could be dangerous if it points to the last element in the container; but the same applies to the solution above. E.g. you'll have to make checks in both cases.

identity
Why use `operator[]` when you already have an iterator? If you want what `it` currently points to, use `*it`. If you want what the iterator after `it` points to, use something like `*(it + 1)` or `std::vector<int>::iterator it2(it); std::advance(it2, 1); *it2;`.Incidentally, the code presented will only work for a `std::vector` (it won't work with a `std::deque` for instance).
Max Lybbert
+5  A: 

C++0x adds a handy utility function, std::next, that copies an iterator, advances it, and returns the advanced iterator. You can easily write your own std::next implementation:

template <typename ForwardIt>
ForwardIt next(ForwardIt it)
{
    return ++it;
}

The actual C++0x std::next allows you to increment any number of times using a second "offset" parameter that is one by default, but that is a bit more involved because you have to overload the function to be efficient for random access iterators while still handling forward and bidirectional iterators.

You can use this in your example like so:

if (iter != mySet.end() && next(iter) != mySet.end() && *next(iter) == *iter + 1)
    mySet.erase(iter);
James McNellis
+1, didn't know that was adopted. Incidentally, `++ move( iter )` does the same thing.
Potatoswatter