在迭代过程中擦除nlohmann::json对象导致分割错误



我有一个简单的数据库,由对象组成,其中字符串包含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()文档:

指出

  1. 使擦除点或擦除点之后的迭代器和引用无效,包括end()迭代器。
  1. 对已删除元素的引用和迭代器无效。其他引用和迭代器不受影响。

这意味着在这行之后:

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)习语,而不是编写脆弱的变异循环。

最新更新