Зарегистрируйте и отмените регистрацию обработчика во время итерации по вектору обработчиков - PullRequest
0 голосов
/ 10 июля 2020

У меня есть очень маленькая программа, которая запускает поток и отправляет события зарегистрированному набору обработчиков. Класс обработчиков выглядит следующим образом.

class Handler
{
public:
    /* OnEvent must return void. This is part of the user interface agreement */
    virtual void OnEvent(struct Event*) = 0;
    virtual ~Handler();
};

Обработчики хранятся внутри вектора

std::vector<Handler*> handlers;

Я могу добавить обработчик к вектору с помощью функции регистрации и удалить обработчик из вектора с помощью отмены регистрации функция. Обработчики могут быть добавлены или удалены в функции OnEvent.

Прототипы ниже

void registerHandler(Handler *h);
void unregisterHandler(Handler *h);

Функция Thread выглядит следующим образом. Он будет блокироваться при событии, и как только событие будет получено, оно отправит это событие каждому обработчику, который находится в векторе.

void thread_function()
{
    struct Event* e = getEvent();


    /* Function will receive an event and will invoke handlers one by one */
    for(auto s = 0; s < handlers.size(); ++s)
    {
        /* Register and unregister function can be called inside OnEvent. */
        handlers[s]->OnEvent();
    }
}

Каким будет наиболее оптимальный способ добавления и удаления обработчика из вектора внутри OnEvent функция?

Моя идея была. Когда регистр вызывается внутри OnEvent, я sh верну обработчик в список обработчиков. Но я никак не могу придумать, как удалить обработчик из вектора. Если я удалю обработчик из вектора, итераторы больше не будут действовать. Будет очень интересно услышать ваши мысли, ребята.

Спасибо

1 Ответ

0 голосов
/ 11 июля 2020

Если вас устраивает, что изменения обработчика вступают в силу только после обработки события, вы можете просто скопировать массив обработчика:

std::vector<Handler*> handlers;

void thread_function(){
  struct Event* e = getEvent();
  std::vector<Handler*> handlersCopy = handlers;
  for(Handler* h : handlersCopy) {
    h->OnEvent();
  }
}

Если вы хотите предотвратить обработку обработчиков, которые удаляются во время обработки, вы можете сделать что-то вроде этого:

std::vector<Handler*> handlers;
bool isDispatching = false;
std::unordered_set<Handler*> disabledHandlers;

void unregisterHandler(Handler *h){
  handlers.erase(handlers.find(h));
  if (isDispatching){
     disabledHandlers.insert(h);
  }
}

void thread_function(){
  struct Event* e = getEvent();
  isDispatching = true;
  std::vector<Handler*> handlersCopy = handlers;
  for(Handler* h : handlersCopy) {
    if(disabledHandlers.find(h) != disabledHandlers.end()){
      continue;
    }
    h->OnEvent();
  }
  isDispatching = false;
  disabledHandlers.clear();
}

...