在迭代期间擦除 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())
会导致段错误,经过一番尝试后我得出一个结论,即不知何故无法追踪它实际迭代的内容。我的结论是真的吗?如果不是那么是什么?我该如何解决?
改变容器操作以使迭代器无效是极其正常的。这是您应该检查的第一件事。
Notes
- Invalidates iterators and references at or after the point of the erase, including the end() iterator.
- 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)
习语的原因,而不是编写脆弱的变异循环。
我有一个简单的数据库,由包含 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())
会导致段错误,经过一番尝试后我得出一个结论,即不知何故无法追踪它实际迭代的内容。我的结论是真的吗?如果不是那么是什么?我该如何解决?
改变容器操作以使迭代器无效是极其正常的。这是您应该检查的第一件事。
Notes
- Invalidates iterators and references at or after the point of the erase, including the end() iterator.
- 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)
习语的原因,而不是编写脆弱的变异循环。