c++ - logico - eliminacion logica mysql
Diferencia entre borrado y eliminación (6)
eliminar no "realmente" elimina nada, porque no puede.
Para "realmente" eliminar los elementos del contenedor, necesita acceder a las API del contenedor. Donde remove solo funciona con iteradores independientemente de a qué contenedores apuntan esos iteradores. Por lo tanto, incluso si remove quiere una "eliminación real", no puede.
Eliminar sobrescribir los elementos "eliminados" por los siguientes elementos que no se eliminaron y, entonces, depende de la persona que llama decidir utilizar el nuevo end
lógico devuelto en lugar del end
original.
En su caso, elimine 1
del vector
eliminado lógicamente, pero el tamaño se mantuvo en 2. Borrar borró realmente los elementos del vector. [del vector new end
al old end
]
La idea principal de remove
es que no puede cambiar el número de elementos y simplemente elimina elementos de un rango según los criterios.
Estoy un poco confundido sobre la diferencia entre el uso del algoritmo std :: remove. Específicamente, no puedo entender qué se elimina cuando uso este algoritmo. Escribí un pequeño código de prueba como este:
std::vector<int> a;
a.push_back(1);
a.push_back(2);
std::remove(a.begin(), a.end(), 1);
int s = a.size();
std::vector<int>::iterator iter = a.begin();
std::vector<int>::iterator endIter = a.end();
std::cout<<"Using iter.../n";
for(; iter != endIter; ++iter)
{
std::cout<<*iter<<"/n";
}
std::cout<<"Using size.../n";
for(int i = 0; i < a.size(); ++i)
{
std::cout<<a[i]<<"/n";
}
La salida fue 2,2 en ambos casos.
Sin embargo, si uso borrar con el remove algo como esto:
a.erase(std::remove(a.begin(), a.end(), 1), a.end());
Obtengo el resultado como 2.
Entonces mis preguntas son:
(1) ¿Hay algún uso de std :: remove que no sea usarlo con la función borrar?
(2) Incluso después de hacer std :: remove, ¿por qué a.size () devuelve 2 y no 1?
Leí el artículo en el libro Effective STL de Scott Meyer sobre el idioma borrar-borrar. Pero todavía estoy teniendo esta confusión.
Enfrenté el mismo problema, tratando de entender la diferencia. las explicaciones que se han dado hasta ahora son correctas sobre el dinero, pero solo las entendí después de ver un ejemplo;
#include <algorithm>
#include <string>
#include <iostream>
#include <cctype>
int main()
{
std::string str1 = "Text with some spaces";
std::string::iterator it = remove(str1.begin(), str1.end(), ''t'');
std::cout << str1 << std::endl;// prints "Tex wih some spaceses"
for (str1.begin();it != str1.end(); ++it)
{
std::cout << *it; //prints "es"
}
}
como puede ver, remove, solo mueve la minúscula ''t'' al final de la cadena, mientras devuelve un nuevo iterador al final de la nueva cadena (la nueva cadena es la cadena anterior hasta donde se insertó el elemento eliminado) ) esta es la razón por la que cuando imprime el iterador que obtuvo de "eliminar"
"Text with some spaces"
^ ^removes both ''t'', then shift all elements forward -1 //what we want to remove
"Text with some spaces"
^ end of string -2 //original state of string
"Tex with some spacess"
^end of string -3 //first ''t'' removed
"Tex wih some spaceses"
^end of string -4 //second ''t'' removed
"Tex wih some spaceses"
^new iterator that remove() returned -5 // the state of string after "remove" and without "erase"
si pasa el iterador que obtuvo del paso 5 a "borrar ()", sabrá borrar desde allí hasta el final de la cadena volviendo a cambiar el tamaño de la secuencia en proceso
Lo más simple que puedo pensar es:
erase()
es algo que puede hacer a un elemento en un contenedor. Dado un iterador / índice en un contenedor, erase( it )
elimina lo que el iterador se refiere desde el contenedor.
remove()
es algo que puedes hacer a un rango, reorganiza ese rango pero no borra nada del rango.
remove()
realidad no elimina elementos del contenedor; solo deshace los elementos no eliminados hacia adelante sobre los elementos eliminados. La clave es darse cuenta de que remove()
está diseñado para funcionar no solo en un contenedor, sino en cualquier par de iteradores directos arbitrarios : eso significa que no puede eliminar los elementos, porque un par de iteradores arbitrarios no necesariamente tiene la capacidad de eliminar elementos
Por ejemplo, los punteros al principio y al final de una matriz C normal son iteradores directos y, como tales, se pueden usar con remove()
:
int foo[100];
...
remove(foo, foo + 100, 42); // Remove all elements equal to 42
¡Aquí es obvio que remove()
no puede cambiar el tamaño de la matriz!
std::remove
no elimina los objetos reales, sino que los empuja hacia el final del contenedor. La eliminación y desasignación real de la memoria se realiza mediante borrado. Asi que:
(1) ¿Hay algún uso de std :: remove que no sea usarlo con la función borrar?
Sí, es útil obtener un par de iteradores para una nueva secuencia sin tener que preocuparse por la desasignación adecuada, etc.
(2) Incluso después de hacer std :: remove, ¿por qué a.size () devuelve 2 y no 1?
El contenedor aún se mantiene en esos objetos, solo tienes un nuevo conjunto de iteradores para trabajar. Por lo tanto, el tamaño sigue siendo lo que solía ser.
¿Qué hace std :: remove?
Aquí está el pseudo código 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;
}
Tenga en cuenta que eliminar simplemente movió hacia arriba los elementos en la secuencia, sobrescribiendo los valores que quería 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 ahora contiene una copia sobrante adicional de 5.
¿Qué hace vector :: borrar?
std::erase
toma el inicio y el final del rango que desea eliminar. No toma el valor que desea eliminar, solo el inicio y el final del rango. Aquí hay un pseudo código de cómo funciona:
erase(Iter first, Iter last)
{
//copy remaining elements from last
while (last != end())
*first++ = *last++;
//truncate vector
resize(first - begin());
}
Entonces, la operación de borrado realmente cambia el tamaño del contenedor y así libera la memoria.
La expresión eliminar-borrar
La combinación de std::remove
y std::erase
permite eliminar los elementos coincidentes del contenedor para que el contenedor se trunque realmente si se eliminan los elementos. He aquí 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 eliminación de expresiones idiomáticas. ¿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
lugar de copiar.