Re[2]: Делегаты на C++
От: Кодт Россия  
Дата: 26.11.08 10:56
Оценка:
Здравствуйте, Anton_86, Вы писали:

<>
Вообще-то, если коллекция пуста, то непонятно, что возвращать.
Т.е.
TRet Invoke(PARAMS)
{
  if(!m_DelegateList.empty())
  {
      for(......) (*it)->Invoke(ARGS);
      return m_DelegateList.back()->Invoke(ARGS);
  }
  else
  {
    // на выбор
    assert(! "нечего вызывать, нечего возвращать, щас вылечу нафиг");
    throw SomeDelegateException();
    return TRet();
  }
}


А ещё остаётся за кадром такой момент, как изменение списка во время его обхода.
Тут нужна или двойная буферизация,
vector<IDelegate*> snapshot; // вектор дешевле списка, поэтому копировать удобнее в него
snapshot.reserve(m_DelegateList.size());
snapshot.insert(m_DelegateList.begin(), m_DelegateList.end());
// далее - как с гусём :)

... или внимательность к свежедобавленным и свежеудаляемым элементам.
Свежедобавленные в конец — будут учитываться, поскольку мы проверяем фактический конец на каждой итерации цикла. (А вот если бы использовали for_each, то там запомнили бы итератор на предпоследний элемент на момент начала работы).
Свежеудалённые — болезненнее, так как может быть удалён текущий элемент, а итератор на него станет невалидным.
Не реентерабельная версия Invoke — в паре с Remove и RemoveAll может выглядеть так
DelegateList::iterator m_next;
.....
void Remove(IComparableDelegate* pDelegate)
{
  .....
  if(it == m_next)
    ++m_next;
  m_DelegateList.erase(it);
  .....
}
void RemoveAll()
{
  .....
  m_next = m_DelegateList.end();
}
TRet Invoke(PARAMS)
{
  DelegateList::iterator it = m_DelegateList.begin();
  while(true)
  {
    if(it == m_DelegateList.end()) { assert(!"всё-таки вылетели!!!"); return TRet(); }
    m_next = it; ++m_next;
    if(m_next == m_DelegateList.end()) { return (*it)->Invoke(ARGS); }
    (*it)->Invoke(ARGS);
    it = m_next;
  }
}

Реентерабельная... у, это сложно.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.