I have a class called Action
, which is essentially a wrapper around a deque of Move
objects.
Because I need to traverse the deque of Moves
both forward and backwards, I have a forward iterator and a reverse_iterator as member variables of the class. The reason for this is becuase I need to know when I have gone one past the "end" of the deque, both when I am going forwards or backwards.
The class looks like this:
class Action { public: SetMoves(std::deque<Move> & dmoves) { _moves = dmoves; } void Advance(); bool Finished() { if( bForward ) return (currentfwd==_moves.end()); else return (currentbck==_moves.rend()); } private: std::deque<Move> _moves; std::deque<Move>::const_iterator currentfwd; std::deque<Move>::const_reverse_iterator currentbck; bool bForward; };
The Advance
function is as follows:
void Action::Advance { if( bForward) currentfwd++; else currentbck++; }
My problem is, I want to be able to retrieve an iterator to the current Move
object, without needing to query whether I am going forwards or backwards. This means one function returning one type of iterator, but I have two types.
Should I forget returning an iterator, and return a const reference to a Move
object instead?
Returns a reverse iterator pointing to the last element in the vector (i.e., its reverse beginning). Reverse iterators iterate backwards: increasing them moves them towards the beginning of the container. rbegin points to the element right before the one that would be pointed to by member end.
Forward Iterator is a combination of Bidirectional and Random Access iterator. Therefore, we can say that the forward iterator can be used to read and write to a container. Forward iterators are used to read the contents from the beginning to the end of a container.
Reverse iterators have a member base()
which returns a corresponding forward iterator. Beware that this isn't an iterator that refers to the same object - it actually refers to the next object in the sequence. This is so that rbegin()
corresponds with end()
and rend()
corresponds with begin()
.
So if you want to return an iterator, then you would do something like
std::deque<Move>::const_iterator Current() const { if (forward) return currentfwd; else return (currentbck+1).base(); }
I would prefer to return a reference, though, and encapsulate all the iteration details inside the class.
This is exactly the sort of problem that prompted the design of STL to start with. There are real reasons for:
I suspect what you're seeing right now is more or less the tip of the iceberg of the real problems. My advice would be to take a step back, and instead of asking about how to deal with the details of the design as it currently stands, ask a somewhat more general question about what you're trying to accomplish, and how best to accomplish that end result.
For those who care primarily about the question in the title, the answer is a heavily qualified "yes". In particular, a reverse_iterator has a base()
member to do that. The qualifications are somewhat problematic though.
The demonstrate the problem, consider code like this:
#include <iostream> #include <vector> #include <iterator> int main() { int i[] = { 1, 2, 3, 4}; std::vector<int> numbers(i, i+4); std::cout << *numbers.rbegin() << "\n"; std::cout << *numbers.rbegin().base() << "\n"; std::cout << *(numbers.rbegin()+1).base() << "\n"; std::cout << *numbers.rend() << "\n"; std::cout << *numbers.rend().base() << "\n"; std::cout << *(numbers.rend()+1).base() << "\n"; }
Running this at this particular moment on my particular machine produces the following output:
4 0 4 -1879048016 1 -1879048016
Summary: with rbegin()
we must add one before converting to a forward iterator to get an iterator that's valid -- but with rend()
we must not add one before converting to get a valid iterator.
As long as you're using X.rbegin()
and X.rend()
as the parameters to a generic algorithm, that's fine--but experience indicates that converting to forward iterators often leads to problems.
In the end, however, for the body of the question (as opposed to the title), the answer is pretty much as given above: the problem stems from trying to create an object that combines the collection with a couple of iterators into that collection. Fix that problem, and the whole business with forward and reverse iterators becomes moot.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With