7

I am moving an iterator backward and forwards through a vector.

I can check if the iterator ran off the end like so:

++my_iterator;
if ( my_iterator == my_vector.end() )
{
    --my_iterator; // if I want to stop the iterator at the end.
    my_iterator = my_vector.begin(); // if I want the iterator to wraparound.
}

But how do I check if it ran off the beginning?

Edit: So can I do this?

--my_iterator;
if ( my_iterator == my_vector.rend() )
{
    my_iterator = my_vector.begin(); // if I want to stop the iterator at the beginning.
    my_iterator = --(my_vector.rbegin()); // if I want the iterator to wraparound.
}

Or do I have to do this?

std::vector< T >::iterator temp_reverse_iterator = reverse_iterator< T >( my_iterator );
++temp_reverse_iterator;
if ( temp_reverse_iterator == my_vector.rend() )
{
    my_iterator = my_vector.begin(); // if I want to stop the iterator at the beginning.
    my_iterator = --(my_vector.end()); // if I want the iterator to wraparound.
}
else
{
    my_iterator = temp_reverse_iterator.base(); // do I need to -- this?
}

And are both of these examples logically sound?

  • Why are you doing this `--my_iterator;` if you are going to assing it after? – Drahakar Sep 07 '11 at 00:23
  • @Drahakar check out the comments. –  Sep 07 '11 at 00:33
  • You need to carefully think about and define your specs - is `my_iterator` ever allowed to be at `my_vector.end()` (the example seems to point to 'no')? If not, you'll need to make sure that `my_vector` can never be empty. – Michael Burr Sep 07 '11 at 00:40
  • @Michael `my_iterator` should never be `my_vector.end()`. and yes, `my_vector` should never be empty. –  Sep 07 '11 at 00:53

3 Answers3

5

You can use my_vector.rend() and myvector.rbegin()

Drahakar
  • 5,986
  • 6
  • 43
  • 58
  • so the `reverse_iterator` return type will work with a conventional `iterator`? –  Sep 07 '11 at 00:23
  • 1
    I don't think that will work for @Jay's requirements. It seems like he wants to have a single bidirectional iterator on a ring buffer. – Robᵩ Sep 07 '11 at 01:27
5

I wonder if it would be easier for you if you used a Boost Circular Buffer instead of a std::vector as your underlying data structure.

But, to answer your actual question: You check for wrapping past the beginning by checking to see if the iterator equals v.begin().

#include <vector>
#include <cassert>

template <class T> void
Increment( typename std::vector<T>::iterator& it, std::vector<T>& v )
{
  assert(v.size() > 0);

  ++it;
  if(it == v.end())
    it = v.begin();
}

template <class T> void
Decrement( typename std::vector<T>::iterator& it, std::vector<T>& v )
{
  assert(v.size() > 0);

  if(it == v.begin())
    it = v.end();
  --it;
}

int main() {
  std::vector<int> v;
  v.push_back(0);
  v.push_back(1);

  std::vector<int>::iterator it;

  it = v.begin();
  Decrement(it, v);
  assert(*it == 1);
  Increment(it, v);
  assert(*it == 0);
}
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
3

You can't really, but you can use a reverse_iterator to cycle backwards through the same vector.

John Humphreys
  • 37,047
  • 37
  • 155
  • 255
  • can you do this? `my_iterator = my_reverse_iterator` and vice-versa? –  Sep 07 '11 at 00:22
  • I believe they are distinct types so it's probably a bad idea. In reality they are identical except their ++ and -- operations are reversed and they seek from .rbegin to .rend though, so maybe you can cast it. I'd say don't do it though :) – John Humphreys Sep 07 '11 at 00:24
  • @Jay: Almost: `my_iterator = my_reverse_iterator.base();` and `my_reverse_iterator = std::reverse_iterator(my_iterator);` (assuming `std::reverse_iterator` is ok to use with your container; it should be...). – James McNellis Sep 07 '11 at 00:25
  • Be carefull that there is an offset between the reverse iterator and its base iterator: `rbegin().base()` is `end()` and not the last element for instance. – Nicolas Grebille Sep 07 '11 at 00:48
  • "You can't really". I disagree. Checking for equality with `begin()` seems to be an obvious answer. – Robᵩ Sep 07 '11 at 01:08