Tengo un vector Necesito eliminar los últimos 3 elementos en él. Describió esta lógica. El programa se bloquea. ¿Cuál podría ser el error?
vector<float>::iterator d = X.end();
for (size_t i = 1; i < 3; i++) {
if (i == 1) X.erase(d);
else X.erase(d - i);
}
d
no existe realmente. Es el valor canario de un pasado que se puede usar solo para encontrar el final de lavector
. No puedes eliminarlo. Luego, tan pronto como borre un iterador, desaparecerá. No puede usarlo con seguridad después para nada, inclusod - i
.Respuestas:
Si hay al menos 3 elementos en el vector, eliminar los últimos 3 elementos es simple: solo use pop_back 3 veces:
Salida:
fuente
Es un comportamiento indefinido pasar el
end()
iterador a laerase()
sobrecarga de 1 parámetro . Incluso si no fuera así,erase()
invalida los iteradores que están "en y después" del elemento especificado, lo qued
deja de ser válido después de la iteración del primer bucle.std::vector
tiene unaerase()
sobrecarga de 2 parámetros que acepta un rango de elementos para eliminar. No necesita un bucle manual en absoluto:Demo en vivo
fuente
Primero,
X.end()
no devuelve un iterador al último elemento del vector, sino que devuelve un iterador al elemento pasado el último elemento del vector, que es un elemento que el vector no posee, por eso cuando intentas borrarlo conX.erase(d)
los bloqueos del programa.En cambio, siempre que el vector contenga al menos 3 elementos, puede hacer lo siguiente:
Que en su lugar va al tercer último elemento, y borra cada elemento después de eso hasta que llegue
X.end()
.EDITAR: Solo para aclarar,
X.end()
es un LegacyRandomAccessIterator que se especifica que tiene una-
operación válida que devuelve otro LegacyRandomAccessIterator .fuente
La definición de
end()
from cppreference es:y ligeramente debajo:
En otras palabras, el vector no tiene ningún elemento al que apunte end (). Al desreferenciar ese no elemento a través del método erase (), posiblemente esté alterando la memoria que no pertenece al vector. Por lo tanto, a partir de ahí pueden pasar cosas feas.
Es la convención habitual de C ++ describir los intervalos como [bajo, alto], con el valor "bajo" incluido en el intervalo y el valor "alto" excluido del intervalo.
fuente
Podrías usar un
reverse_iterator
:Hay pocas cosas para mencionar:
reverse_iterator rit
comienza en el último elemento de lavector X
. Esta posición se llamarbegin
.erase
requiere clásicoiterator
para trabajar. Obtenemos esorit
llamandobase
. Pero ese nuevo iterador apuntará al siguiente elemento desderit
adelante.rit
antes de llamarbase
yerase
Además, si desea obtener más información
reverse_iterator
, le sugiero que visite esta respuesta .fuente
Un comentario (ahora eliminado) en la pregunta decía que "no hay operador para un iterador". Sin embargo, el siguiente código compila y funciona en ambos
MSVC
yclang-cl
, con el estándar establecido enC++17
oC++14
:La definición proporcionada para el
operator-
es la siguiente (en el<vector>
encabezado):Sin embargo, ciertamente no soy un abogado de lenguaje C ++, y es posible que esta sea una de esas extensiones 'peligrosas' de Microsoft. Me interesaría saber si esto funciona en otras plataformas / compiladores.
fuente
-
están definidos para esos tipos de iteradores.operator-
definido para los iteradores, podría usarstd::advance()
o en sustd::prev()
lugar.Esta declaración
tiene un comportamiento indefinido
Y esta declaración intenta eliminar solo el elemento anterior al último elemento
porque tienes un bucle con solo dos iteraciones
Necesitas algo como lo siguiente.
La salida del programa es
fuente