删除后的C ++映射迭代
|
我找不到执行此操作的实例,所以我希望有人可以帮助我。我在一个类中定义了一个地图,如下所示:
std::map<std::string, TranslationFinished> translationEvents;
TranslationFinished是boost :: function。我的类中有一个方法会遍历此映射,并像下面这样调用每个函数:
void BaseSprite::DispatchTranslationEvents()
{
for(auto it = translationEvents.begin(); it != translationEvents.end(); ++it)
{
it->second(this);
}
}
但是,it->second(this);
调用的函数可以使用以下函数从translationEvents映射中删除元素(通常是其自身):
bool BaseSprite::RemoveTranslationEvent(const std::string &index)
{
bool removed = false;
auto it = translationEvents.find(index);
if (it != translationEvents.end())
{
translationEvents.erase(it);
removed = true;
}
return removed;
}
这样做会导致当DispatchTranslationEvents()
尝试递增迭代器时调试断言失败。有没有一种方法可以安全地遍历映射,而迭代期间的函数调用可能会从映射中删除元素?
提前致谢
编辑:偶然C / Pd错误的删除事件代码。立即修复。
没有找到相关结果
已邀请:
7 个回复
babsoft
在这两个选项中,我显然希望使用[2],因为您要将回调与处理程序的实现分离。就是说,[2]中的回调函数对其所容纳的容器一无所知。 [1]具有较高的耦合度(回调知道容器),并且由于在代码中从多个位置更改了容器,因此很难推理。一段时间后,您甚至可能回头看一下代码,认为这是一个怪异的循环(不记得回调会自行删除),然后将其重构为更合理的符号,例如
。 删除其他回调 对于可以删除任何其他回调的更复杂的问题,这完全取决于您可以做出的妥协。在简单的情况下,仅在完成迭代后才删除其他回调,您可以提供一个单独的成员函数,该函数将保留要删除的元素,然后在循环完成后立即将其全部删除:
如果需要立即删除元素(即即使尚未调用它们也不应在此迭代中调用),则可以通过在执行调用之前检查是否将其标记为删除来修改该方法。标记可以通过两种方法完成,通用的方法是将容器中的值类型更改为
,其中bool指示其是否存在。在这种情况下,如果可以更改所包含的对象,则可以这样做:
请注意,由于回调可以删除容器中的任何元素,因此您不能随便擦除,因为当前的回调可能会删除已访问的迭代器。再说一遍,您可能不在乎将空函子保留一段时间,因此可以忽略它并随即执行go10ѭ。标记为要删除的已访问元素将在下一遍清除。
锹缄
(显然)使要删除的迭代器无效,但不会使其余映射无效。 这意味着: 如果您删除当前元素之外的任何其他元素,那么您是安全的,并且 如果删除当前元素,则必须首先获取下一个迭代器,以便您可以继续进行迭代(这就是大多数容器的why10 the函数返回下一个迭代器的原因)。
不是,因此您必须手动执行此操作) 假设您只删除了当前元素,则可以这样简单地重写循环:
否则(如果函数可以删除任何元素),可能会变得更加复杂。
扫窟
淑灯
如果要保留
函数,则应返回true,否则将其返回false。
陷牡彭拈峰
删除元素后,迭代器将无效,因此删除该元素后就无法再使用该迭代器来增加操作。但是,删除一个元素不会影响地图实现IIRC中的其他元素。因此,后缀++将首先复制迭代器,然后立即增加迭代器,然后返回复制值,这意味着在擦除操作之前增加迭代器,这对于您的要求应该是安全的。
炬卤遁蝎变
防止在循环本身中调用无效事件,并清除所有“已删除”事件:
一个明显的警告是,如果一个事件被迭代,然后又被删除,则在当前的分发循环中,它没有机会再次被迭代以被删除。 这意味着该事件的实际删除将推迟到下一次运行分发循环时进行。
稀瓣囊