When we are iterating in reverse direction, I see that most people use the following structure:
for (auto it = vec.rbegin(); it != vec.rend(); it++)
{
// block of code //
}
But for a long time, I have a doubt about using this, and I want to know why the following code does not work.
As we know, the last element will have the highest index than any element index in the array, and the array is going to take contiguous memory.
My primary doubt is when iterating backwards, why shouldn't we use it--?
I want the reason why the following code is not going to work. I am running the loop from rbegin, that is the last element, and I am going until the first element. I am decrementing it by one in every iteration.
for (auto it = vec.rbegin(); it >= vec.begin(); it--)
{
cout << *it << endl;
}
Even the below code is not working, why?
for(auto it = vec.rbegin(); it >= vec.begin(); it++)
{
cout << *it << endl;
}
First of all, in the given codes, the for loop's conditions are making issue due to type-mismatch.
The vec.rbegin() gives the std::vector::reverse_iterator, and the vec.begin() gives the std::vector::iterator; those are different types and can not be compared. Hence, you get compiler errors in those places.
When iterating backwards, why shouldn't we use it--?
See the following reference picture from std::reverse_iterator
When you use rbegin(), you start from the last element. In order to advance further (like every iterator implementation) it uses the operator++. Advance here means, iterating backwards direction, because the starting point is the last element. Therefore, you should be using it++ or ++it instead.
For the last for loop example, however, there is only a type-mismatch issue. Using ✱std::reverse_iterator::base(), you could get/ convert the reverse iterator to the corresponding base iterator, and it can be compared with the vec.begin().
That means the following change will make it work:
for (auto it = vec.rbegin(); it.base() != vec.begin(); ++it)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
std::cout << *it << " ";
}
See a demo
Side Note:
Even though, the above is possible, I would strongly suggest use the same iterators for comparison, which provides the code more natural look, and easy to understand for the fellow devs and less error-prone.
✱Read more: Can I convert a reverse iterator to a forward iterator?
In all, it is just a design issue, the designer designed the begin, rbegin, end, rend in that way.
Take an example of a container with three elements {1,2,3}.
begin() points to 1, end() points to the position after 3
rbegin() points to 3, rend() points to the position before 1.
You can understand rbegin() as a special data struct of a special pointer (aka iterator) such that + operator would be overloaded into -.
You can but not recommended to mix rbegin() with begin() cause they are different things. And mixing is always error-prone for most of the time.
Reverse iterators are designed to mimic forward iterators (and iterators in general are designed to mimic pointers), so algorithms can be written in an agnostic way that works with both types. All iterators advance with operator++ and decrement with operator-- , where
forward iterators advance in a forward direction and decrement in a backwards direction
reverse iterators advance in a backward direction and decrement in a forward direction
Related
std::multimap<std::string, std::string> authors;
authors.insert ({{"Steven,King", "Cujo"}, {"Jesse,James", "The Highlight"}});
auto it = authors.begin();
auto retVal2 = authors.erase(it+1);
for (auto &i : authors){
std::cout << i.first << " " << i.second << std::endl;
}
Is it not allowed to add values to the iterator to move to the desired location in the multimap?
In vectors this can be done.
Please clarify if there is anyway about this?
thank you.
std::multimap::iterator is a bidirectional iterator. A bidirectional iterator does not have operator+ because it can only advance one at a time making operator+ a very slow function. Maybe you're comparing it to the iterator of something like std::vector or std::array. However, those are random access iterators where operator+ can work in constant time.
Since you only need to add it by 1, you can easily replace it+1 with std::next(it). If you want to make a new iterator n elements after it you can also do std::next(it, n). Like std::next, there's also std::prev for going backwards. If you want to modify it itself, you can use operator++/operator-- (which act like how you would expect them to) or use std::advance(it, n) to go n elements forward or backward (There's no opposite of std::advance like std::recede, to make your iterator go back n should be a negative number).
How to get the last element of an std::unordered_map?
myMap.rbegin() and --myMap.end() are not possible.
There is no "last element" in a container that is unordered.
You might want an ordered container, e.g. std::map and access the last element with mymap.rbegin()->first (Also see this post)
EDIT:
To check if your iterator is going to hit the end, simply increment it (and possibly save it in a temporary) and check it against mymap.end(), or, even cleaner : if (std::next(it) == last)
In your comments, it appears your goal is to determine if you are on the last element when iterating forward. This is a far easier problem to solve than finding the last element:
template<class Range, class Iterator>
bool is_last_element_of( Range const& r, Iterator&& it ) {
using std::end;
if (it == end(r)) return false;
if (std::next(std::forward<Iterator>(it)) == end(r)) return true;
return false;
}
the above should work on any iterable Range (including arrays, std containers, or custom containers).
We check if we are end (in which case, we aren't the last element, and advancing would be illegal).
If we aren't end, we see if std::next of us is end. If so, we are the last element.
Otherwise, we are not.
This will not work on iterators that do not support multiple passes.
You cant. by definition, the element is not stored based on some sort of order. the key is hashed first and that's why O(1) search is possible. if you wanna check whether a key exists in the unordered_map or not, u can use this code:
std::unordered_map dico;
if(dico.count(key)!=0){
//code here
}
std::unordered_map::iterator last_elem;
for (std::unordered_map::iterator iter = myMap.begin(); iter != myMap.end(); iter++)
last_elem = iter;
// use last_elem, which now points to the last element in the map
This will give you the last element in whatever order the map gives them to you.
Edit: You need to use std::unordered_map<YourKeyType, YourValueType> instead of just std::unordered_map. I just wrote it like this because you did not provide the type in your question.
Alternatively, as suggested by vsoftco (thanks), you could declare both last_elem and iter as decltype(myMap)::iterator.
(If you're compiling with the MSVC++ compiler, then you will need to add typedef decltype(myMap) map_type; and then instead of decltype(myMap)::iterator use map_type::iterator.)
.end() is an iterator to the "element past the last element". That's why you compare it like this when you loop through a map:
for (auto it = myMap.begin(); it != myMap.end(); ++it) // '!=' operator here makes it possible to only work with valid elements
{
}
So you want the "last" element (whatever that may be, because it's not really guaranteed to be the last in an unordered map, since it ultimately depends on how the key was hashed and in which "bucket" it ends up in). Then you need: --myMap.end()
More specifically, .end() is a function, that returns an iterator, same as .begin() returns an iterator. Since there is no .rbegin() in an std::unordered_map, you have to use -- (the decrement operator):
auto it = --myMap.end();
To access the key you use it->first, to access the value you use it->second.
The accepted answer seems wrong. Unordered_map does have the last element even though the key-value pair is not stored in sorted order. Since the iterator of unorered_map is forwar_iterator(LegacyForwardIterator), the cost to find the last element is O(n). Yakk - Adam gave the correct answer. Essentially, you have to iterator the container from begin to end. At each iteration, you have to check whether the next element is end(); if yes then you are at the last element.
You cannot call prev(it) or --it. There will be no syntax error, but you will have a runtime error (more likely segmentation fault) when using the prev(it) or --it. Maybe next version of compiler can tell you that you have an logic error.
It may not be the best solution, performance-wise, but in C++11 and later, I use a combination of std::next() and size() to jump all elements from the beginning of the map, as shown below:
std::unordered_map<int,std::string> mapX;
...
if (mapX.size() > 0) {
std::unordered_map<int,std::string>::iterator itLast =
std::next(mapX.begin(), mapX.size() - 1);
...
According to some STL documentation I found, inserting or deleting elements in an std::list does not invalidate iterators. This means that it is allowed to loop over a list (from begin() to end()), and then add elements using push_front.
E.g., in the following code, I initialize a list with elements a, b and c, then loop over it and perform a push_front of the elements. The result should be cbaabc, which is exactly what I get:
std::list<std::string> testList;
testList.push_back("a");
testList.push_back("b");
testList.push_back("c");
for (std::list<std::string>::iterator itList = testList.begin(); itList != testList.end(); ++itList)
testList.push_front(*itList);
for (std::list<std::string>::const_iterator itList = testList.begin(); itList != testList.end(); ++itList)
std::cout << *itList << std::endl;
When I use reverse iterators (loop from rbegin() to rend()) and use push_back, I would expect similar behavior, i.e. a result of abccba. However, I get a different result:
std::list<std::string> testList;
testList.push_back("a");
testList.push_back("b");
testList.push_back("c");
for (std::list<std::string>::reverse_iterator itList = testList.rbegin(); itList != testList.rend(); ++itList)
testList.push_back(*itList);
for (std::list<std::string>::const_iterator itList = testList.begin(); itList != testList.end(); ++itList)
std::cout << *itList << std::endl;
The result is not abccba, but abcccba. That's right there is one additional c added.
It looks like the first push_back also changes the value of the iterator that was initialized with rbegin(). After the push_back it does not point anymore to the 3rd element in the list (which was previously the last one), but to the 4th element (which is now the last one).
I tested this with both Visual Studio 2010 and with GCC and both return the same result.
Is this an error? Or some strange behavior of reverse iterators that I'm not aware of?
The standard says that iterators and references remain valid during an insert. It doesn't say anything about reverse iterators. :-)
The reverse_iterator returned by rbegin() internally holds the value of end(). After a push_back() this value will obviously not be the same as it was before. I don't think the standard says what it should be. Obvious alternatives include the previous last element of the list, or that it stays at the end if that is a fixed value (like a sentinel node).
Technical details: 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.
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).
I think to understand this, it's best to start by re-casting the for loop as a while loop:
typedef std::list<std::string> container;
container testList;
testList.push_back("a");
testList.push_back("b");
testList.push_back("c");
container::reverse_iterator itList = testList.rbegin();
while (itList != testList.rend()) {
testList.push_back(*itList);
++itList;
}
Along with that, we have to understand how a reverse_iterator works in general. Specifically a reverse_iterator really points to the element after the one you get when you dereference it. end() yields an iterator to just after the end of the container -- but for things like arrays, there's no defined way to point to just before the beginning of a container. What C++ does instead is have the iterator start from just after the end, and progress to the beginning, but when you dereference it, you get the element just before where it actually points.
That means your code actually works like this:
After that, you get pretty much what you expect, pushing back B and then A, so you end up with ABCCCBA.
Try using an iterator for both. Try:
std::list<std::string>::iterator i = testList.end();
and reverse through with --i
I recently learned about the right way to work with reverse iterators in C++ (specifically when you need to erase one). (See this question and this one.)
This is how you're supposed to do it:
typedef std::vector<int> IV;
for (IV::reverse_iterator rit = iv.rbegin(), rend = iv.rend();
rit != rend; ++rit)
{
// Use 'rit' if a reverse_iterator is good enough, e.g.,
*rit += 10;
// Use (rit + 1).base() if you need a regular iterator e.g.,
iv.erase((rit + 1).base());
}
But I think thought this is much better (Don't do this, not standards compliant, as MooingDuck points out):
for (IV::iterator it = iv.end(), begin = iv.begin();
it-- != begin; )
{
// Use 'it' for anything you want
*it += 10;
iv.erase(it);
}
Cons:
You tell me. What's wrong with it?
It's not standards compliant, as MooingDuck points out. That pretty much overrules any of the possible advantages below.
Pros:
Uses a familiar idiom for reverse for-loops
Don't have to remember (or explain) the +1
Less typing
Works for std::list too: it = il.erase(it);
If you erase an element, you don't have to adjust the iterator
If you erase, you don't have to recompute the begin iterator
The reason for reverse iterators is that the standard algorithms do not know how to iterate over a collection backwards. For example:
#include <string>
#include <algorithm>
std::wstring foo(L"This is a test, with two letter a's involved.");
std::find(foo.begin(), foo.end(), L'a'); // Returns an iterator pointing
// to the first a character.
std::find(foo.rbegin(), foo.rend(), L'a').base()-1; //Returns an iterator
// pointing to the last A.
std::find(foo.end(), foo.begin(), L'a'); //WRONG!! (Buffer overrun)
Use whichever iterator results in clearer code.
For what it's worth, Scott Meyers' Effective STL recommends that you just stick with a regular ol' iterator (Item 26).
I'm writing some cross-platform code between Windows and Mac.
If list::end() "returns an iterator that addresses the location succeeding the last element in a list" and can be checked when traversing a list forward, what is the best way to traverse backwards?
This code workson the Mac but not on Windows (can't decrement beyond first element):
list<DVFGfxObj*>::iterator iter = m_Objs.end();
for (iter--; iter!=m_Objs.end(); iter--)// By accident discovered that the iterator is circular ?
{
}
this works on Windows:
list<DVFGfxObj*>::iterator iter = m_Objs.end();
do{
iter--;
} while (*iter != *m_Objs.begin());
Is there another way to traverse backward that could be implemented in a for loop?
Use reverse_iterator instead of iterator.
Use rbegin() & rend() instead of begin() & end().
Another possibility, if you like using the BOOST_FOREACH macro is to use the BOOST_REVERSE_FOREACH macro introduced in Boost 1.36.0.
The best/easiest way to reverse iterate a list is (as already stated) to use reverse iterators rbegin/rend.
However, I did want to mention that reverse iterators are implemented storing the "current" iterator position off-by-one (at least on the GNU implementation of the standard library).
This is done to simplify the implementation, in order for the range in reverse to have the same semantics as a range forward [begin, end) and [rbegin, rend)
What this means is that dereferencing an iterator involves creating a new temporary, and then decrementing it, each and every time:
reference
operator*() const
{
_Iterator __tmp = current;
return *--__tmp;
}
Thus, dereferencing a reverse_iterator is slower than an normal iterator.
However, You can instead use the regular bidirectional iterators to simulate reverse iteration yourself, avoiding this overhead:
for ( iterator current = end() ; current != begin() ; /* Do nothing */ )
{
--current; // Unfortunately, you now need this here
/* Do work */
cout << *current << endl;
}
Testing showed this solution to be ~5 times faster for each dereference used in the body of the loop.
Note: Testing was not done with the code above, as that std::cout would have been the bottleneck.
Also Note: the 'wall clock time' difference was ~5 seconds with a std::list size of 10 million elements. So, realistically, unless the size of your data is that large, just stick to rbegin() rend()!
You probably want the reverse iterators. From memory:
list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin();
for( ; iter != m_Objs.rend(); ++iter)
{
}
As already mentioned by Ferruccio, use reverse_iterator:
for (std::list<int>::reverse_iterator i = s.rbegin(); i != s.rend(); ++i)
This should work:
list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin();
for (; iter!= m_Objs.rend(); iter++)
{
}