在迭代期间擦除 nlohmann::json 对象会导致分段错误

erasing nlohmann::json object during iteration causes segmentation fault

我有一个简单的数据库,由包含 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, removing\n";
    m_jsonData.erase(it);
    } else {
    /*
    */
    }
}

只要不调用 m_jsonData.erase(it);,此代码就可以正常工作。当它发生时,在下一次迭代中 std::stoi(it.key()) 会导致段错误,经过一番尝试后我得出一个结论,即不知何故无法追踪它实际迭代的内容。我的结论是真的吗?如果不是那么是什么?我该如何解决?

改变容器操作以使迭代器无效是极其正常的。这是您应该检查的第一件事。

nlohnmann::json::erase() 的文档:

Notes

  1. Invalidates iterators and references at or after the point of the erase, including the end() iterator.
  1. References and iterators to the erased elements are invalidated. Other references and iterators are not affected.

这意味着在这一行之后:

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::erase was added in C++20, and previously std::remove_if 来支持 erase(remove_if(...), end) 习语的原因,而不是编写脆弱的变异循环。