c ++ 11 — c ++ list :: erase не работает должным образом / странное поведение с итераторами

В настоящее время я разрабатываю протокол маршрутизации на C ++ для использования в сетях, устойчивых к сбоям. Для этого ему необходимо распространять копии сообщений (а не самого сообщения) по сети. Чтобы проверить его производительность в простом моделировании, я абстрагировал большинство факторов, в результате чего пакеты моделировались простыми структурами, содержащими случайное значение данных, идентификатор, источник и место назначения.

Чтобы этот протокол работал, я определил следующие переменные класса:

  1. std::list<packet> buffer — этот список содержит все пакеты, которые этот узел имеет для передачи.
  2. std::list<packet*> toTransmit — при каждой сетевой возможности между 2 или более узлами каждый узел определяет, какие пакеты следует передавать, поэтому этот отдельный список указателей сохраняется
  3. std::list<packet*>::iterator priority_ix — передача происходит в две фазы, пакеты с первым приоритетом передаются, с priority_ix отслеживание местоположения в toTransmit список.
  4. std::list<packet*>::iterator normal_ix — только после передачи всех приоритетных пакетов может начаться нормальная передача, отслеживаемая этим итератором.

Из-за того, что узел получает приоритетный пакет, он должен немедленно переслать, priority_ix может быть сброшено к началу списка, в то время как обычные передачи должны продолжаться с того места, где он был прерван, поэтому необходимы два отдельных итератора.

Теперь о странном поведении. Обычно я использую ix = mylist.erase(ix) удалить элемент, на который я сейчас указываю, после этого не имея недействительного итератора. Это всегда работало для меня, однако что-то не так в одном конкретном методе в моем коде. Этот метод работает с полученными ACK-сообщениями, что может привести к удалению пакета, на который указывает один или оба этих итератора.

void Node::receiveAck(u_int packet_id) {
std::list<packet>::iterator ix = std::find(buffer.begin(), buffer.end(), packet_id);
if(ix != buffer.end()) {
if((**priority_ix) == packet_id && (**normal_ix) == packet_id) {
priority_ix = toTransmit.erase(priority_ix);
normal_ix = priority_ix;
} else if((**priority_ix) == packet_id) {
priority_ix = toTransmit.erase(priority_ix);
}
else if((**normal_ix) == packet_id) {
normal_ix = toTransmit.erase(normal_ix);
}

else {
toTransmit.remove(&(*ix));
}
buffer.erase(ix);
}
}

Этому методу СЛЕДУЕТ делать то, что он проверяет, указывают ли два итератора на удаляемый пакет, и проверяет их перемещение перед удалением пакета из обоих toTransmit а также buffer, Кстати, если кому-то интересно, я написал метод оператора == для сравнения пакетов с u_ints, позволяющий std::find найти правильный пакет в bufferЯ подтвердил, что он действительно вводит правильные операторы if с ix имея правильное значение.

Однако вместо этого происходит то, что при вызове std::list::erase функция, он увеличивает итератор до следующего допустимого местоположения, но фактически не удаляет элемент из списка, в результате чего недопустимые указатели сохраняются в toTransmit вызывая SEGFAULTs где-то позже.

Я пытался обойти проблему, просто делая ++priority_ix и / или ++normal_ix в операторе if с последующим toTransmit.remove(&(*ix)) после всех заявлений. Это очищает элементы от toTransmitОднако, если увеличенные итераторы указывали на последний элемент в toTransmit, он будет указывать на тот же элемент после увеличения, а не на toTransmit.end(), снова приводя к SEGFAULTs где-то еще в коде.

Странно, однако, что buffer.erase(ix) Кажется, работает нормально. Я очень разочарован этой проблемой, так как часто использую итераторы и никогда не сталкиваюсь с подобным поведением. Любая помощь или указания, где посмотреть в коде, очень ценится.

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]