2012-02-06 14 views
9

Estoy iterando sobre un conjunto de funciones de devolución de llamada. Las funciones se invocan durante la iteración y pueden conducir a cambios drásticos en el contenedor real de las funciones establecidas.Iteración de un contenedor cambiante

Lo que estoy haciendo ahora es:

  1. hacer una copia del conjunto original
  2. iterar sobre la copia, pero por cada elemento compruebe si todavía existe en el conjunto original

Comprobación porque la existencia de cada elemento es súper dinámica, pero también parece bastante lenta.

¿Hay otras propuestas para abordar este caso?

Editar: aquí está el código real: enfoques

// => i = event id 
    template <class Param> 
    void dispatchEvent(int i, Param param) { 

     EventReceiverSet processingNow; 

     const EventReceiverSet& eventReceiverSet = eventReceiverSets[i]; 
     std::copy(eventReceiverSet.begin(), eventReceiverSet.end(), std::inserter(processingNow, processingNow.begin())); 

     while (!processingNow.empty()) { 
      EventReceiverSet::iterator it = processingNow.begin(); 
      IFunction<>* function = it->getIFunction(); /// get function before removing iterator 
      processingNow.erase(it); 

      // is EventReceiver still valid? (may have been removed from original set) 
      if (eventReceiverSet.find(ERWrapper(function)) == eventReceiverSet.end()) continue; // not found 

      function->call(param); 
     } 
    }; 
+0

Por "set" Qué quiere decir 'std :: set <>'? Si no, ¿cuál es el tipo de contenedor real? – ildjarn

+0

Bueno, quería dejar este genérico, pero sí, es un estándar :: set –

Respuesta

4

Dos básicos vienen a la mente:

  1. utilizar un enfoque basado en tareas (con la colección bloqueado, tareas de empuje en una cola para cada elemento, luego suelte a todas las partes para que hagan el trabajo y esperen hasta que finalice). Todavía necesitará una verificación para ver si el elemento para la tarea actual todavía está presente/actual en la colección cuando la tarea realmente está comenzando.

    • esto podría aprovechar cerraduras lector-escritor para los controles, lo cual es generalmente más rápido que las exclusiones mutuas en toda regla (especialmente con más lectores que escritores)

  2. utilizar una estructura de datos concurrente (me refiero , uno que es adecuado para acceso multiproceso sin bloqueo explícito). Las siguientes bibliotecas contienen implementaciones de estructuras de datos concurrentes:

(añadiendo enlaces en breve)

3

hay una manera de hacerlo en dos pasos: primero, pasar por el conjunto original y hacer un conjunto de elementos de acción. Luego revise el conjunto de elementos de acción y aplíquelos al conjunto original.

Un elemento de acción es una clase base con subclases. Cada subclase toma en un conjunto, y lleva a cabo una operación específica en él, por ejemplo:

struct set_action { 
    virtual void act(std::set<int> mySet) const; 
}; 
class del_action : public set_action { 
private: 
    int item; 
public: 
    del_action(int _item) : item(_item) {} 
    virtual void act(std::set<int> mySet) const { 
     // delete item from set 
    } 
}; 
class upd_action : public set_action { 
private: 
    int from, to; 
public: 
    upd_action(int _from, int _to) : from(_from), to(_to) {} 
    virtual void act(std::set<int> mySet) const { 
     // delete [from], insert [to] 
    } 
}; 

Ahora puede crear una colección de set_action* s en la primera pasada, y ejecutarlos en el segundo paso.

3

Las operaciones que modifican la estructura set son insert() y erase().

Al iterar, considere usando el iterador devuelto por las operaciones de mutación.

it = myset.erase(it); 

http://www.cplusplus.com/reference/stl/set/erase/

+0

El enlace que citó dice: void set :: erase (posición del iterador); –

Cuestiones relacionadas