For some reason the following code fails. You can't simply erase a reverse_iterator by using its base() method.
#include <set>
#include <iostream>
int main()
{
std::set<int> setOfInts;
setOfInts.insert(1);
setOfInts.insert(2);
setOfInts.insert(3);
std::set<int>::reverse_iterator rev_iter = setOfInts.rbegin();
std::set<int>::reverse_iterator nextRevIter = setOfInts.rbegin();
++nextIter;
while ( rev_iter != setOfInts.rend())
{
// Find 3 and try to erase
if (*rev_iter == 3)
{
// SEGFAULT HERE
setOfInts.erase( rev_iter.base());
}
rev_iter = nextRevIter;
++nextRevIter;
}
}
How does one go about correctly doing the above? Given a reverse_iterator that corresponds to something you want to erase, how do you erase it?
Note, erase won't take reverse_iterators unfortunately. It wants the real thing.
list::clear() is an inbuilt function in C++ STL which is declared in header file. list::clear(), clears the whole list. In other words the clear() removes all the elements present in the list container and leaves the container with size 0.
Return Value: This function returns an iterator pointing to the element in the list container which followed the last element erased from the list container. Below programs illustrates the list::erase() function. Program 1: Erasing a single element. CPP.
C++ Iterators Reverse Iterators A reverse iterator is made from a bidirectional, or random access iterator which it keeps as a member which can be accessed through base() . To iterate backwards use rbegin() and rend() as the iterators for the end of the collection, and the start of the collection respectively.
Apparently the solution is what base() returns is 1 off. The following identity holds for a reverse_iterator:
&*(reverse_iterator(i)) == &*(i - 1)
Or in other words, the reverse_iterator is always one pass the regular iterator it is the base of. Not sure why.
Simply change
// SEGFAULT HERE
setOfInts.erase( rev_iter.base());
to
// WORKS!
setOfInts.erase( --rev_iter.base());
I'm definitely curious though as to why the identity above makes sense.
Coming back into work and trying this in visual studio, I see the above solution doesn't quite work. The "nextIter" becomes invalid on the erase. Instead, you need to save away the temporary from the erase to get the next iterator instead of keeping around a nextIter like above.
set<int>::iterator tempIter = setOfInts.erase(--rev_iter.base());
rev_iter = setOfInts.erase(tempIter);
So the final solution is
int main()
{
using namespace std;
set<int> setOfInts;
setOfInts.insert(1);
setOfInts.insert(2);
setOfInts.insert(3);
set<int>::reverse_iterator rev_iter = setOfInts.rbegin();
while ( rev_iter != setOfInts.rend())
{
// Find 3 and try to erase
if (*rev_iter == 3)
{
cout << "Erasing : " << *rev_iter;
set<int>::iterator tempIter = setOfInts.erase( --rev_iter.base());
rev_iter = set<int>::reverse_iterator(tempIter);
}
else
{
++rev_iter;
}
}
}
Note, associative containers do not return an iterator from erase. So this solution wouldn't work for map, multimap, etc.
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