Estoy tratando de hacer algo como esto:
for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
if ( *i == pCursor )
{
m_CursorStack.erase( i );
break;
}
}
Sin embargo, borrar toma un iterador y no un iterador inverso. ¿Hay alguna forma de convertir un iterador inverso en un iterador regular u otra forma de eliminar este elemento de la lista?
i != m_CursorStack.rend()
. En cambio, escribei = m_CursorStack.rbegin(), end = m_CursorStack.rend(); i != end;
. Es decir, inicialice un iterador que pueda mantener para comparar repetidamente, suponiendo que la posición final no cambiará como un efecto secundario de su cuerpo de bucle.std::remove
?Respuestas:
Después de más investigación y pruebas encontré la solución. Aparentemente de acuerdo con el estándar [24.4.1 / 1] la relación entre i.base () e i es:
(de un artículo del Dr. Dobbs ):
Por lo tanto, debe aplicar un desplazamiento al obtener la base (). Por lo tanto, la solución es:
EDITAR
Actualización para C ++ 11.
reverse_iterator no
i
ha cambiado:reverse_iterator
i
es avanzado:Esto me parece mucho más claro que mi solución anterior. Use lo que necesite.
fuente
m_CursorStack.erase( (++i).base())
(hombre, hacer esto con iteradores inversos me duele la cabeza ...). También debe tenerse en cuenta que el artículo DDJ se incorpora al libro "Efectivo STL" de Meyer.*
, pero estamos hablando de a qué elemento apuntaría si fuera abase
ellos, que es un elemento a la derecha. No soy tan fanático de las soluciones--(i.base())
o(++i).base()
ya que mutan el iterador. Prefiero(i+1).base()
que funcione también.Tenga en cuenta que
m_CursorStack.erase( (++i).base())
puede ser un problema si se usa en unfor
bucle (consulte la pregunta original) porque cambia el valor de i. La expresión correcta esm_CursorStack.erase((i+1).base())
fuente
iterator j = i ; ++j
, porquei+1
no funciona en un iterador, pero esa es la idea correctam_CursorStack.erase(boost::next(i).base())
con Boost. o en C ++ 11m_CursorStack.erase(std::next(i).base())
Esto requiere la
-std=c++11
bandera (paraauto
):fuente
Es curioso que todavía no haya una solución correcta en esta página. Entonces, el siguiente es el correcto:
En el caso del iterador directo, la solución es sencilla:
En caso de iterador inverso, debe hacer lo mismo:
Notas:
reverse_iterator
desde un iteradorstd::list::erase
fuente
Si bien usar el método
reverse_iterator
'sbase()
y decrementar el resultado funciona aquí, vale la pena señalar quereverse_iterator
no se les da el mismo estado que lositerator
s normales . En general, debe preferir lositerator
s areverse_iterator
s regulares (así como aconst_iterator
s yconst_reverse_iterator
s), precisamente por razones como esta. Vea el Diario del Doctor Dobbs para una discusión en profundidad de por qué.fuente
fuente
Y aquí está el fragmento 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 al borrar el primer o el último elemento:
fuente
Si no necesita borrar todo a medida que avanza, para resolver el problema, puede usar el idioma borrar-eliminar:
std::remove
intercambia todos los elementos en el contenedor que coincidenpCursor
hasta el final y devuelve un iterador al primer elemento coincidente. Luego, elerase
uso de un rango se borrará de la primera partida e irá al final. Se conserva el orden de los elementos que no coinciden.Esto podría funcionar más rápido si está utilizando un
std::vector
, donde borrar en medio del contenido puede implicar muchas copias o movimientos.O, por supuesto, las respuestas anteriores que explican el uso de
reverse_iterator::base()
son interesantes y vale la pena saber, para resolver el problema exacto enunciado, diría questd::remove
encaja mejor.fuente
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 falte algo, la declaración 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.
fuente
Para complementar las respuestas de otros y debido a que me topé con esta pregunta mientras buscaba sobre std :: string sin mucho éxito, aquí va una respuesta con el uso de std :: string, std :: string :: erase y std :: reverse_iterator
Mi problema fue borrar el nombre de archivo de una imagen de una cadena de nombre de archivo completa. Originalmente se resolvió con std :: string :: find_last_of, pero investigo una forma alternativa con std :: reverse_iterator.
Esto utiliza algoritmos, iteradores y encabezados de cadena.
fuente
El iterador inverso es bastante difícil de usar. Así que solo usé el iterador general. 'r' Comienza desde el último elemento. Cuando encuentre algo para borrar. bórrelo y vuelva al siguiente iterador. Por ejemplo, cuando elimine el tercer elemento, señalará el cuarto elemento actual. y nuevo 3er. Por lo tanto, debe reducirse 1 para moverse a la izquierda
fuente