我有一个简单的数据库,由对象组成,其中字符串包含unix时间作为键,字符串包含指令作为值
我想遍历数据库并擦除键值小于当前时间的对象(因此擦除日期在当前日期之前的对象)
for (auto it = m_jsonData.begin(); it != m_jsonData.end(); it++) {
if (std::stoi(it.key()) <= (std::time(NULL))) {
std::cout << "command is behind schedule, removingn";
m_jsonData.erase(it);
} else {
/*
*/
}
}
只要不调用m_jsonData.erase(it);
,此代码就可以正常工作。当它这样做的时候,在下一次迭代中,std::stoi(it.key())
会导致段错误,在玩了一会儿之后,我得出一个结论,它不知何故失去了它实际迭代的轨迹。我的结论是对的吗?如果不是,那是什么?我该如何修复它?
改变容器操作使迭代器失效是极其正常的。这是你应该首先检查的事情之一。
nlohnmann::json::erase()
文档:
- 使擦除点或擦除点之后的迭代器和引用无效,包括end()迭代器。
- 对已删除元素的引用和迭代器无效。其他引用和迭代器不受影响。
这意味着在这行之后:
m_jsonData.erase(it);
迭代器it
不能用于任何,包括递增到下一个元素。
幸运的是,文档还指出将返回被删除元素的后继元素,因此您可以只写
for (auto it = m_jsonData.begin(); it != m_jsonData.end(); ) {
if (std::stoi(it.key()) <= (std::time(NULL))) {
it = m_jsonData.erase(it);
} else {
++it;
}
}
请注意,当我说这是非常正常的,这是因为标准容器经常有类似的行为。请参阅文档中的示例,但这是每个人都应该知道的:
std::vector::erase
迭代器失效std::unordered_map::erase
迭代器失效- 等。
这正是在c++ 20中添加std::erase
的原因,之前提供std::remove_if
以支持erase(remove_if(...), end)
习语,而不是编写脆弱的变异循环。