¿Qué hace std :: remove?
Aquí está el código de seudo de std::remove
. Tómese unos segundos para ver qué está haciendo y luego lea la explicación.
Iter remove(Iter start, Iter end, T val) {
Iter destination = start;
//loop through entire list
while(start != end) {
//skip element(s) to be removed
if (*start == val) {
start++;
}
else //retain rest of the elements
*destination++ = *start++;
}
//return the new end of the list
return destination;
}
Observe que eliminar simplemente movió hacia arriba los elementos de la secuencia, sobrescribiendo los valores que desea eliminar. Entonces, los valores que quería eliminar se han ido, pero ¿cuál es el problema? Digamos que tienes vector con valores {1, 2, 3, 4, 5}. Después de llamar a quitar para val = 3, el vector ahora tiene {1, 2, 4, 5, 5}. Es decir, 4 y 5 se movieron hacia arriba de modo que 3 se ha ido del vector, pero el tamaño del vector no ha cambiado. Además, el final del vector contiene ahora una copia restante adicional de 5.
¿Qué hace vector :: borrar?
std::erase
toma el inicio y el final del rango que desea deshacerse.No toma el valor que desea eliminar, solo el inicio y el final del rango. Aquí está pseudo código para saber cómo funciona:
erase(Iter first, Iter last)
{
//copy remaining elements from last
while (last != end())
*first++ = *last++;
//truncate vector
resize(first - begin());
}
lo tanto la operación de borrado realmente cambia el tamaño del envase y así libera la memoria.
El idioma remove-borrado
La combinación de std::remove
y std::erase
le permite eliminar elementos coincidentes del recipiente de manera que recipiente en realidad obtener truncado si se eliminaran elementos. Aquí se muestra cómo hacerlo:
//first do the remove
auto removed = std::remove(vec.begin(), vec.end(), val);
//now truncate the vector
vec.erase(removed, vec.end());
Esto se conoce como eliminar-borrar idioma. ¿Por qué está diseñado así? La idea es que la operación de encontrar elementos es más genérica e independiente del contenedor subyacente (solo depende de los iteradores). Sin embargo, la operación de borrado depende de cómo el contenedor está almacenando la memoria (por ejemplo, puede haber enlazado la lista en lugar de la matriz dinámica). Por lo tanto, STL espera que los contenedores hagan su propio borrado a la vez que proporcionan una operación genérica de "eliminación" para que todos los contenedores no tengan que implementar ese código. En mi opinión, el nombre es muy engañoso y std::remove
debería haberse llamado std::find_move
.
Nota: El código anterior es estrictamente pseudocódigo. La implementación real de STL es más inteligente, por ejemplo, al usar std::move
en lugar de copiar.
Encuentro que la parte más difícil de esto es borrar y eliminar significar casi lo que se guarda en inglés, por lo que es fácil olvidar cuál es cuál –