How to call erase with a reverse iterator

Viewed 85762

I am trying to do something like this:

for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
    if ( *i == pCursor )
    {
        m_CursorStack.erase( i );
        break;
    }
}

However erase takes an iterator and not a reverse iterator. is there a way to convert a reverse iterator to a regular iterator or another way to remove this element from the list?

13 Answers

Funny that there is no correct solution on this page yet. So, the following is the correct one:

In case of the forward iterator the solution is straight forward:

std::list< int >::iterator i = myList.begin();
while ( i != myList.end() ) {
  if ( *i == to_delete ) {
    i = myList.erase( i );
  } else {
    ++i;
  } 
}

In case of reverse iterator you need to do the same:

std::list< int >::reverse_iterator i = myList.rbegin();
while ( i != myList.rend() ) {
  if ( *i == to_delete ) {
    i = decltype(i)(myList.erase( std::next(i).base() ));
  } else {
    ++i;
  } 
}

Notes:

  • You can construct a reverse_iterator from an iterator
  • You can use the return value of std::list::erase

And here is the piece of code to convert the result of erase back to a reverse iterator in order to erase an element in a container while iterating in the reverse. A bit strange, but it works even when erasing the first or last element:

std::set<int> set{1,2,3,4,5};

for (auto itr = set.rbegin(); itr != set.rend(); )
{    
    if (*itr == 3)
    {
        auto it = set.erase(--itr.base());
        itr = std::reverse_iterator(it);            
    }
    else
        ++itr;
}

To complement other's answers and because I stumbled upon this question whilst searching about std::string without much success, here goes a response with the usage of std::string, std::string::erase and std::reverse_iterator

My problem was erasing the an image filename from a complete filename string. It was originally solved with std::string::find_last_of, yet I research an alternative way with std::reverse_iterator.

std::string haystack("\\\\UNC\\complete\\file\\path.exe");
auto&& it = std::find_if( std::rbegin(haystack), std::rend(haystack), []( char ch){ return ch == '\\'; } );
auto&& it2 = std::string::iterator( std::begin( haystack ) + std::distance(it, std::rend(haystack)) );
haystack.erase(it2, std::end(haystack));
std::cout << haystack;  ////// prints: '\\UNC\complete\file\'

This uses algorithm, iterator and string headers.

reverse iterator is quite hard to use. So just used general iterator. 'r' It start from last element. When find something to erase. erase it and return next iterator. eg when delete 3rd element it will pointing current 4th element. and new 3rd. So it should be decreased 1 to move left

void remchar(string& s,char c)
{      
    auto r = s.end() - 1;
    while (r >= s.begin() && *r == c)
    {
        r = s.erase(r);
        r -= 1;
    }
}

If m_CursorStack is a vector, you can erase by taking index:

m_CursorStack.erase(m_CursorStack.begin() + m_CursorStack.size() + int(m_CursorStack.rbegin() - i) - 1);

The reason that m_map.erase((++r_iter).base() doesn't work in a loop is that erase() would invalidate the ++r_iter!! We just need to use the return value from the erase().

Related