目前我正在开发一种用于中断容忍网络的c ++路由协议。为此,它需要通过网络传播消息的副本(而不是消息本身)。为了在简单的模拟中测试其性能,我抽象了大多数因素,导致数据包被包含随机数据值,id,源和目标的简单结构模拟。
为了使这个协议起作用,我定义了以下类变量:
std::list<packet> buffer
- 此列表包含此节点可用于传输的所有数据包。std::list<packet*> toTransmit
- 在2个或更多节点之间的每个联网机会,每个节点确定应传输哪些数据包,因此保留这个单独的指针列表std::list<packet*>::iterator priority_ix
- 传输分两个阶段进行,第一个优先级数据包被传输,priority_ix
跟踪toTransmit
列表中的位置。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
中找到正确的数据包,我已经验证它确实进入了更正ix
具有正确值的if语句。
然而,反而发生的是,在调用std::list::erase
函数时,它将迭代器递增到下一个有效位置,但实际上并未从列表中删除该元素,从而导致无效指针存储在{{ 1}}稍后在某处导致SEGFAULT。
我试图通过在if语句中执行toTransmit
和/或++priority_ix
来解决此问题,然后在所有语句之后执行++normal_ix
。这会很好地从toTransmit.remove(&(*ix))
清除元素,但是如果递增的迭代器指向toTransmit
中的最后一个元素,它将在递增后指向相同的元素而不是toTransmit
,再次导致SEGFAULTs在代码中的其他地方。
奇怪的是,toTransmit.end()
似乎正常工作。我对此问题感到非常沮丧,因为我经常使用迭代器,似乎从未遇到过这种行为。非常感谢您在代码中查看的任何帮助或方向。