Cómo llamar a borrar con un iterador inverso

Estoy tratando de hacer algo como esto:

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

Sin embargo, el borrado toma un iterador y no un iterador inverso. ¿Hay alguna manera de convertir un iterador inverso en un iterador regular u otra forma de eliminar este elemento de la lista?

Después de algunas investigaciones y pruebas, encontré la solución. Aparentemente de acuerdo con el estándar [24.4.1 / 1] la relación entre i.base () y yo es:

 &*(reverse_iterator(i)) == &*(i - 1) 

(de un artículo del Dr. Dobbs ):

texto alternativo

Entonces necesita aplicar un desplazamiento al obtener la base (). Por lo tanto, la solución es:

 m_CursorStack.erase( --(i.base()) ); 

EDITAR

Actualización para C ++ 11.

reverse_iterator i ha cambiado:

 m_CursorStack.erase( std::next(i).base() ); 

reverse_iterator i está avanzado:

 std::advance(i, 1); m_CursorStack.erase( i.base() ); 

Encuentro esto mucho más claro que mi solución anterior. Use lo que necesite.

Tenga en cuenta que m_CursorStack.erase( (++i).base()) puede ser un problema si se usa en un ciclo for (ver pregunta original) porque cambia el valor de i. La expresión correcta es m_CursorStack.erase((i+1).base())

… u otra forma de eliminar este elemento de la lista?

Esto requiere el -std=c++11 (para auto ):

 auto it=vt.end(); while (it>vt.begin()) { it--; if (*it == pCursor) //{ delete *it; it = vt.erase(it); //} } 

Al usar el reverse_iterator base() reverse_iterator y disminuir el resultado funciona aquí, vale la pena señalar que los reverse_iterator s no reciben el mismo estado que los iterator regulares. En general, deberías preferir iterator regulares a reverse_iterator s (así como a const_iterator sy const_reverse_iterator s), por razones precisamente como esta. Ver el Diario del Doctor Dobbs para una discusión en profundidad de por qué.

 typedef std::map TMap; TMap Map; ....... for( TMap::const_reverse_iterator It = Map.rbegin(), end = Map.rend(); It != end; It++ ) { TMap::const_iterator Obsolete = It.base(); // conversion into const_iterator It++; Map.erase( Obsolete ); It--; } 

Si no necesita borrar todo a medida que avanza, entonces para resolver el problema, puede usar la expresión borrar-eliminar:

 m_CursorStack.erase(std::remove(m_CursorStack.begin(), m_CursorStack.end(), pCursor), m_CursorStack.end()); 

std::remove intercambia todos los elementos del contenedor que coinciden con pCursor hasta el final y devuelve un iterador al primer elemento de coincidencia. Luego, el erase utiliza un rango se borrará del primer partido y llegará hasta el final. El orden de los elementos no coincidentes se conserva.

Esto podría funcionar más rápido si usa un std::vector , donde borrar en el medio de los contenidos puede implicar una gran cantidad de copia o movimiento.

Por supuesto, las respuestas anteriores que explican el uso de reverse_iterator::base() son interesantes y vale la pena conocerlas, para resolver el problema exacto planteado, yo diría que std::remove es una mejor opción.

Solo quería aclarar algo: en algunos de los comentarios y respuestas anteriores, la versión portátil para borrar se menciona como (++ i) .base (). Sin embargo, a menos que me falta algo, la statement correcta es (++ ri) .base (), lo que significa que ‘incrementa’ el reverse_iterator (no el iterador).

Me encontré con la necesidad de hacer algo similar ayer y esta publicación fue útil. Gracias a todos.

Y aquí está la pieza de código para convertir el resultado de borrar de nuevo a un iterador inverso para borrar un elemento en un contenedor mientras se itera en el reverso. Un poco extraño, pero funciona incluso cuando se borra el primer o el último elemento:

 std::set 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; } 

Es curioso que en esta página todavía no haya una solución correcta. Entonces siguiendo el correcto:

En el caso del iterador directo, la solución es directa:

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

en el caso de un iterador inverso, debe hacer lo mismo:

 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; } } 

notas:

 1) You can build a reverse_iterator from an iterator 2) You use the return value of std::list::erase