Pregunta

Estoy escribiendo un programa que es más o menos así:

#include <list>

list<MyClass> things;

class MyClass {
   // some stuff

   void remove() {
       things.remove_if(THING_IS_ME);
   }
};

¿Qué necesito para escribir en lugar de THING_IS_ME?

En otras palabras, estoy usando una lista STL global como un conjunto de cosas. En algún momento, un objeto que está en la lista reconoce que es redundante y quiere a) obtener en sí retira de la lista, y b) obtener sí destructed.

¿Cómo se hace esto?

No he escrito en C ++ durante unos 15 años y estoy un poco confundido por esta página aquí: http://www.cplusplus.com/reference/algorithm/remove_if/

¿Qué son estos predicados? ¿El C ++ tiene funciones de orden superior ahora?

¿Fue útil?

Solución

(originalmente una serie de comentarios, pero reescrito como una respuesta después de descubrir lo que el PO en realidad quería hacer.)

¿Se da cuenta de que el almacén de contenedores STL copias de cosas que se insertan, ¿verdad? Eso significa que las instancias de MyClass mejor que sea comparable (por ejemplo a través de operator==) -. No se puede simplemente comparar las direcciones, ya que siempre serán diferentes

Si tener copias de MiClase no tiene sentido, entonces usted está probablemente mejor con un recipiente puntero .

Una vez dicho esto, utiliza el lenguaje C ++ la copia-semántica por defecto. El lenguaje requiere que haga cosas como referencias explícitas en el código. Le recomiendo que usted toma un buen libro C ++ o se le ser disparado por cuestiones de este tipo en el futuro.

Otros consejos

Las cosas han cambiado drásticamente en C ++ en los últimos 15 años. En la propuesta de una biblioteca que incorpore sus ideas de programación genérica recibieron la aprobación final del comité ANSI / ISO de julio de de 1994 Alexander Stepanov. Esta biblioteca que hoy llamamos convenientemente el TEL posteriormente se convirtió en una biblioteca estándar de C ++. La historia de la STL es casi tan fascinante como las ideas detrás de él, y que sin duda vale la pena la lectura.

La función std::remove_if() que ha encontrado es sólo un reflejo más de esta filosofía que se convirtió en parte de la identidad moderna C ++ 's. En resumen, esta es una función genérica que funcionará en cualquier contenedor (secuencia) de los elementos y con cualquier (cosa que actúa como una) condición. Para este efecto, debe proporcionar la función de dos cosas:

  1. un par de iteradores que delimitan la gama de elementos que desea trabajar en;
  2. y un predicado que, cuando se invoca en un elemento, devuelve verdadero si el elemento se va a retirar y falso en caso contrario.

Como resulta que, en este caso el predicado que queremos es el de la igualdad. Y debido a que es una tarea tan común a los elementos quitan basa en la igualdad de la norma también proporciona la función std::remove(), lo que supone un predicado de igualdad implícita. Por supuesto, usted debe asegurarse de que los elementos pueden comparar:

bool operator==(const MyClass& a, const MyClass& b)
{
    // return true if the two are equal, and false otherwise.
}

A continuación, podemos utilizar nuestro predicado para eliminar elementos de tipo MyClass:

std::remove(things.begin(), things.end(), *this);  // if *this == elem

Hay que recordar que la función estándar std::remove() trabaja en cualquier contenedor, incluso los que no han sido creados aún. Debido a que cada tipo de contenedor tiene su propia forma de eliminación de elementos, esta función no puede realmente realizar la extracción sin conocer los detalles de implementación del contenedor que funciona en. Así que en lugar, los elementos de permutas de función std::remove() alrededor de tal manera que los elementos "eliminado" están en el extremo del recipiente. Luego, devuelve un iterador que señala en el primer elemento de los elementos consecutivos "eliminado".

typedef std::list<MyClass>::iterator iter;
iter first_removed = std::remove(things.begin(), things.end(), *this);

Por último, realmente eliminar elementos llamando a la función de eliminación del contenedor específico, que funciona en una sola posición en la lista o en una serie de elementos consecutivos para eliminar:

things.erase(first_removed, things.end());

No es raro ver este tipo de código en una sola línea:

things.erase(std::remove(things.begin(), things.end(), *this),
             things.end());

Todo esto puede parecer abrumador y complicado, pero tiene algunas ventajas. Por un lado, este diseño de la biblioteca estándar es compatible con la programación dinámica. También permite que la biblioteca estándar para ofrecer envases con interfaces muy delgadas, así como algunas funciones libres que trabajar en muchos tipos diferentes de recipientes. Se le permite crear rápidamente un contenedor y al instante ganar todas las características de la biblioteca estándar para trabajar con él. Como alternativa, se le permite escribir rápidamente una función genérica que al instante funciona con todos los contenedores estándar -. Los que ya están escritos y los que no están escritas sin embargo

En primer lugar, un simple bucle escrito a mano:

for( list<MyClass>::iterator it = things.begin(); it != things.end(); /*  */ ) {
    if( qualifiesForDelete( *it ) ) {
        it = things.erase( it );
    }
    else {
        ++it;
    }
}

En segundo lugar, utilizando el algoritmo de la remove_if. remove_if siendo un algoritmo, en contraposición a una función miembro de list, no puede realmente eliminar cualquier elemento, sino que se mueve el ser-eliminan elementos-a-hacia el final de la lista. Posteriormente erase tiene que ser llamado. Este es un modismo muy importante, de borrado de un modismo eliminar , que debe ser aprendida.

things.erase( 
    remove_if( things.begin(), things.end(), deletionPredicate ), 
    things.end() 
);

donde deletionPredicate es una función o función a objetos que toma un único argumento de tipo y vuelve bool. se consideran que ser eliminado Los elementos para los que se devuelve true.

La función remove_if toma tres parámetros: dos iteradores que definen el rango que está trabajando, y un predicado (función de prueba de que los rendimientos bool). El inicio de iterador apunta al primer elemento que desee trabajar en; los puntos de iterador extremo al elemento después del último elemento de la gama.

En el ejemplo de la página se enlazó a , el predicado es la línea de código que dice

bool IsOdd (int i) { return ((i%2)==1); }

Para hacer que el código hace lo que quiere, que había necesidad de escribir algo como esto:

things.remove_if(things.begin(), things.end(), SomePredicateFunction);

y que le define como tal SomePredicateFunction (reemplazando true con una prueba apropiada):

bool SomePredicateFunction (MyClass c) { return true; }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top