How Reverse Iterator in C++ works - c++

am beginner to c++ and i want to know how operator ++ moves iterator backward. As i know iterator.begin() and iterator.end() returns pointer to fist index and last index respectively.
vector<int>::iterator it = myvector.begin();
when we do it++ it will move to next index. this is clear to me but i am completely confused with reverse iterator.
vector<int>::reverse_iterator rit = myvector.rbegin();
when we do rit++ it will move to backward. I want know how this is implemented in case of reverse iterator. Is it operator overloading or something which i don't know. Please give me right way to understand these things.
please give more detail knowledge.

_***************_
^begin ++---> ^end
^rend <---++ ^rbegin

As i know iterator.begin() and iterator.end() returns pointer to fist index and last index respectively.
Close, but not necessarily:
they return iterators, not pointers....
end() returns an iterator that's notionally "past" the last valid index.
Internally the vector iterators normally do store pointers though, and a ++ or -- on the iterator goes through a forwarding overloaded operator to perform a corresponding ++ or -- on the pointer.
For reverse iterators, the overloaded operator++ simply performs a -- on the pointer, and vice versa. For example, the Visual C++ library on my computer does this in class _Revranit, from which reverse_iterator is derived:
_Myt& operator++()
{
--current;
return (*this);
}
_Myt operator++(int)
{
_Myt _Tmp = *this;
--current;
return (_Tmp);
}

When you do it++ or rit++ they don't really mean "move forward or backward in the collection", they both mean "move to the next element you want to iterate over".
If you use begin(), you're saying "I want to iterate forwards", so it++ moves forwards.
If you use rbegin(), you're saying "I want to iterate backwards", so rit++ moves backwards.

Yes, this is operator overloading. When you do rit++, the compiler internally translates that do
rit.operator++(0);
Here, operator++ is a method of the reverse iterator class that knows how to move the iterator. The dummy integer argument is needed to differentiate between prefix and postfix operator++.

Yes, there's a reverse_iterator::operator++ overload which advances "backwards" from the last element to one-before-the-beginning.
The behavior is equivalent to (the page on cppreference might contain another possible implementation)
reverse_iterator operator++(int)
{
reverse_iterator __tmp(*this);
--current; // This is an internal iterator
return __tmp;
}
Notice that how this is exactly accomplished might vary from implementation to implementation. As far as you comply with the standard requirements, you have some degrees of freedom.

The relationship between a reverse iterator r and the iterator i it is constructed from is:
&*r == &*(i-1)
If end is the one-past-the-end element in a sequence, then the first element in the reversed sequence points to *(end – 1 )

Related

Are the end iterators always in the rhs of the comparison?

From what I have found in my testing range-based standard algorithms and containers always do the following comparison it!=c.end() aka the end iterator is on the right of the != operator and I want to know if there's an standard or some warranty that the following will not appear on the STL implementation c.end()!=it
I'm curious because I'm building an iterators library and my != operator looks something like this
bool operator!=(const Iterator& lhs, const Iterator& rhs)
{
return lhs._validate();
}
Which is valid as long as the rhs is always the end iterator
When ever it!=c.end() is false, technically end iterator is on the both sides of the comparison.
There is no requirement to write it!=c.end() instead of c.end()!=it nor is there a guarantee that latter won't be written. Both are equally allowed. Furthermore it is entirely possible that neither iterator of the comparison is an end iterator: c.begin()!=c.begin() is perfectly fine. As such, your suggestion won't work.
Writing the changing "variable" on the left and the "constant" with a known property on the right is conventional in programming as well as natural in relation to English: We ask "Is the iterator at the end?" rather than "Is at the end the iterator?".
23.3.1 In general [iterator.requirements.general]
1 Iterators are a generalization of pointers that allow a C ++ program to work with different data structures (for example, containers and ranges) in a uniform manner.
2 Since iterators are an abstraction of pointers, their semantics are a generalization of most of the semantics of pointers in C ++ . This ensures that every function template that takes iterators works as well with regular pointers.
Comparison of pointers is well-defined even if any of them is a null pointer or a past-the-end pointer. They have commutative property, that is result stays the same when the order of arguments is reversed. So comparison functions working with iterators are expected to behave in similar manner and not just randomly dereference arguments or require one of them not to be past-the-end iterator.

C++: Is it safe to delete post-increment operator on custom iterators?

According to the C++ reference, the requirement of a forward iterator is that it supports the post-increment operator (i.e. iterator operator++(int) and
I am wondering if it's safe to disallow this operation on a custom forward iterator, i.e.
custom_iterator operator++(int) = delete; // disallow post-increment, i.e. it++
custom_iterator operator++() { ... } // we only define pre-increment, i.e. ++it
and assume that STL will never call it++ on such a custom iterator it, when it is passed as an argument to a STL generic algorithm such as copy, sort, fill etc.?
A quote from the official C++11 standard regarding this matter would be the most useful one, but answers such as "most implementation do this and that" are also welcome.
All iterators must be both pre- and post-incrementable. This is part of the requirements for both input and output iterators. See C++11 §24.2[iterator.requirements] Tables 107 and 108. It's rather hard to quote the tables, but in both tables, the expression ++r and r++ must be valid for an iterator r.
So, no. If you are implementing a new iterator type, instances of that type must be both pre- and post-incrementable, and all STL algorithms and any other functions that take iterators may assume post-incrementability.
Because iterators must also be copy constructible, it is generally trivial to implement the postincrement operator in terms of the preincrement operator. For example,
MyIterator operator++(int)
{
MyIterator original(*this);
++*this;
return original;
}

vector::erase and reverse_iterator

I have a collection of elements in a std::vector that are sorted in a descending order starting from the first element. I have to use a vector because I need to have the elements in a contiguous chunk of memory. And I have a collection holding many instances of vectors with the described characteristics (always sorted in a descending order).
Now, sometimes, when I find out that I have too many elements in the greater collection (the one that holds these vectors), I discard the smallest elements from these vectors some way similar to this pseudo-code:
grand_collection: collection that holds these vectors
T: type argument of my vector
C: the type that is a member of T, that participates in the < comparison (this is what sorts data before they hit any of the vectors).
std::map<C, std::pair<T::const_reverse_iterator, std::vector<T>&>> what_to_delete;
iterate(it = grand_collection.begin() -> grand_collection.end())
{
iterate(vect_rit = it->rbegin() -> it->rend())
{
// ...
what_to_delete <- (vect_rit->C, pair(vect_rit, *it))
if (what_to_delete.size() > threshold)
what_to_delete.erase(what_to_delete.begin());
// ...
}
}
Now, after running this code, in what_to_delete I have a collection of iterators pointing to the original vectors that I want to remove from these vectors (overall smallest values). Remember, the original vectors are sorted before they hit this code, which means that for any what_to_delete[0 - n] there is no way that an iterator on position n - m would point to an element further from the beginning of the same vector than n, where m > 0.
When erasing elements from the original vectors, I have to convert a reverse_iterator to iterator. To do this, I rely on C++11's §24.4.1/1:
The relationship between reverse_iterator and iterator is
&*(reverse_iterator(i)) == &*(i- 1)
Which means that to delete a vect_rit, I use:
vector.erase(--vect_rit.base());
Now, according to C++11 standard §23.3.6.5/3:
iterator erase(const_iterator position); Effects: Invalidates
iterators and references at or after the point of the erase.
How does this work with reverse_iterators? Are reverse_iterators internally implemented with a reference to a vector's real beginning (vector[0]) and transforming that vect_rit to a classic iterator so then erasing would be safe? Or does reverse_iterator use rbegin() (which is vector[vector.size()]) as a reference point and deleting anything that is further from vector's 0-index would still invalidate my reverse iterator?
Edit:
Looks like reverse_iterator uses rbegin() as its reference point. Erasing elements the way I described was giving me errors about a non-deferenceable iterator after the first element was deleted. Whereas when storing classic iterators (converting to const_iterator) while inserting to what_to_delete worked correctly.
Now, for future reference, does The Standard specify what should be treated as a reference point in case of a random-access reverse_iterator? Or this is an implementation detail?
Thanks!
In the question you have already quoted exactly what the standard says a reverse_iterator is:
The relationship between reverse_iterator and iterator is &*(reverse_iterator(i)) == &*(i- 1)
Remember that a reverse_iterator is just an 'adaptor' on top of the underlying iterator (reverse_iterator::current). The 'reference point', as you put it, for a reverse_iterator is that wrapped iterator, current. All operations on the reverse_iterator really occur on that underlying iterator. You can obtain that iterator using the reverse_iterator::base() function.
If you erase --vect_rit.base(), you are in effect erasing --current, so current will be invalidated.
As a side note, the expression --vect_rit.base() might not always compile. If the iterator is actually just a raw pointer (as might be the case for a vector), then vect_rit.base() returns an rvalue (a prvalue in C++11 terms), so the pre-decrement operator won't work on it since that operator needs a modifiable lvalue. See "Item 28: Understand how to use a reverse_iterator's base iterator" in "Effective STL" by Scott Meyers. (an early version of the item can be found online in "Guideline 3" of http://www.drdobbs.com/three-guidelines-for-effective-iterator/184401406).
You can use the even uglier expression, (++vect_rit).base(), to avoid that problem. Or since you're dealing with a vector and random access iterators: vect_rit.base() - 1
Either way, vect_rit is invalidated by the erase because vect_rit.current is invalidated.
However, remember that vector::erase() returns a valid iterator to the new location of the element that followed the one that was just erased. You can use that to 're-synchronize' vect_rit:
vect_rit = vector_type::reverse_iterator( vector.erase(vect_rit.base() - 1));
From a standardese point of view (and I'll admit, I'm not an expert on the standard): From §24.5.1.1:
namespace std {
template <class Iterator>
class reverse_iterator ...
{
...
Iterator base() const; // explicit
...
protected:
Iterator current;
...
};
}
And from §24.5.1.3.3:
Iterator base() const; // explicit
Returns: current.
Thus it seems to me that so long as you don't erase anything in the vector before what one of your reverse_iterators points to, said reverse_iterator should remain valid.
Of course, given your description, there is one catch: if you have two contiguous elements in your vector that you end up wanting to delete, the fact that you vector.erase(--vector_rit.base()) means that you've invalidated the reverse_iterator "pointing" to the immediately preceeding element, and so your next vector.erase(...) is undefined behavior.
Just in case that's clear as mud, let me say that differently:
std::vector<T> v=...;
...
// it_1 and it_2 are contiguous
std::vector<T>::reverse_iterator it_1=v.rend();
std::vector<T>::reverse_iterator it_2=it_1;
--it_2;
// Erase everything after it_1's pointee:
// convert from reverse_iterator to iterator
std::vector<T>::iterator tmp_it=it_1.base();
// but that points one too far in, so decrement;
--tmp_it;
// of course, now tmp_it points at it_2's base:
assert(tmp_it == it_2.base());
// perform erasure
v.erase(tmp_it); // invalidates all iterators pointing at or past *tmp_it
// (like, say it_2.base()...)
// now delete it_2's pointee:
std::vector<T>::iterator tmp_it_2=it_2.base(); // note, invalid iterator!
// undefined behavior:
--tmp_it_2;
v.erase(tmp_it_2);
In practice, I suspect that you'll run into two possible implementations: more commonly, the underlying iterator will be little more than a (suitably wrapped) raw pointer, and so everything will work perfectly happily. Less commonly, the iterator might actually try to track invalidations/perform bounds checking (didn't Dinkumware STL do such things when compiled in debug mode at one point?), and just might yell at you.
The reverse_iterator, just like the normal iterator, points to a certain position in the vector. Implementation details are irrelevant, but if you must know, they both are (in a typical implementation) just plain old pointers inside. The difference is the direction. The reverse iterator has its + and - reversed w.r.t. the regular iterator (and also ++ and --, > and < etc).
This is interesting to know, but doesn't really imply an answer to the main question.
If you read the language carefully, it says:
Invalidates iterators and references at or after the point of the erase.
References do not have a built-in sense of direction. Hence, the language clearly refers to the container's own sense of direction. Positions after the point of the erase are those with higher indices. Hence, the iterator's direction is irrelevant here.

Iterator value differs from reverse iterator value after conversion

I have the following code:
int main()
{
vector<int> v;
for(int i = 0; i < 10; ++i)
v.push_back(i);
auto it = v.begin() + 3;
cout << "Iterator: " << *it << endl;
vector<int>::reverse_iterator revIt(it);
cout << "Reverse iterator: " << *revIt << endl;
}
After running this code I get the following output:
Iterator: 3
Reverse iterator: 2
Could someone explain why the 2 values differ ?
Reverse iterators 'correspond' to a base iterator with an offset of one element because of how rbegin() and rend() have to be represented using base iterators that are valid (end() and begin() respectively). For example, rend() cannot be represented by an interator that 'points' before the container's begin() iterator, although that's what it logically represents. So rend()'s 'base iterator' is begin(). Therefore, rbegin()'s base iterator becomes end().
A reverse iterator automatically adjusts for that offset when it is dereferenced (using the * or -> operators).
An old article by Scott Meyers explains the relationship in detail along with a nice picture:
Guideline 3: Understand How to Use a reverse_iterator’s Base iterator
Invoking the base member function on a reverse_iterator yields the
“corresponding” iterator, but it’s not really clear what that means.
As an example, take a look at this code, which puts the numbers 1-5 in
a vector, sets a reverse_iterator to point to the 3, and sets an
iterator to the reverse_iterator’s base:
vector<int> v;
// put 1-5 in the vector
for (int i = 1; i <= 5; ++i) {
v.push_back(i);
}
// make ri point to the 3
vector<int>::reverse_iterator ri =
find(v.rbegin(), v.rend(), 3);
// make i the same as ri's base
vector<int>::iterator i(ri.base());
After executing this code, things can be thought of as looking like
this:
This picture is nice, displaying the characteristic offset of a
reverse_iterator and its corresponding base iterator that mimics the
offset of rbegin() and rend() with respect to begin() and end(), but
it doesn’t tell you everything you need to know. In particular, it
doesn’t explain how to use i to perform operations you’d like to
perform on ri.
Looks like the documentation says they do that to handle past-the-end elements, i.e. if you reverse an iterator that is past the end, the new reverse iterator points to the last element.
The first paragraph of 24.5.1 Reverse iterators says:
Class template reverse_iterator is an iterator adaptor that iterates from the end of the sequence defined by its underlying iterator to the beginning of that sequence. The fundamental relation between a reverse iterator and its corresponding iterator i is established by the identity:
&*(reverse_iterator(i)) == &*(i - 1).
The value returned by rend() cannot point before begin(), because that is not valid. So it was decided that rend() should contain the value of begin() and all other reverse iterators be shifted one position further. The operator* compensates for this and accesses the correct element anyway.
Reverse iterator looks always "one before" then the forward, since its range is shifted by one:
Forward iterator goes from begin() (the first element) to end() (past the last: [begin-end) is opened at the end side)
Reverse iterator goes from rbegin() { return reverse_iterator(end()); } to rend() { return reverse_iterator(begin()); } by definition, but also has to walk the open range [rbegin-rend) having rbegin to be the last (not "past the last") and rend to be "before the first" (not "the first") hence a 1 difference to be accommodated.

Is it safe to increase an iterator inside when using it as an argument?

Currently I'm trying to erase a sequence of iterators from a set, however GCC's standard library seems to be broken because std::set::erase(iterator) should return the an iterator (next iterator), however in GCC it returns void (which is standard?)
Anyways I want to write:
myIter = mySet.erase(myIter);
But GCC doesn't like it...
So Is it safe to write this instead?
mySet.erase(myIter++);
Edit: And yes I'm checking against mySet.end();
There is no problem with
mySet.erase(myIter++);
The order of operation is well-defined: myIter is copied into myTempIter, myIter is incremented, and myTempIter is then given to the erase method.
For Greg and Mark: no, there is no way operator++ can perform operations after the call to erase. By definition, erase() is called after operator++ has returned.
First, reread the standard and you'll see that the prototype of the set::erase method is:
void erase(iterator position);
However, the associative containers in the STL are "stable", as erasing an element do not affect the iterators on the other elements. This means that the following line is valid:
iterator to_erase = myIter++;
mySet.erase(to_erase);
// Now myIter is still on the next element