我将 {string, MyStruct}
对象插入到 unordered_map 中,稍后遍历 unordered_map 并选择删除该元素。但是,在删除元素之前,我有一个断言显示 unordered_map 为空。
这是我的插页:
my_umap.insert(std::make_pair(key.toString(), my_struct));
该结构包含一个记录其插入时间的成员。然后我定期检查 map 并删除在 unordered_map 中时间过长的元素:
for(auto it = my_umap.begin(); it != my_umap.end(); ++it){
MyStruct& myStruct = it->second;
const bool deleteEntry = myStruct.ts.IsElapsed(std::chrono::seconds(5));
if(deleteEntry){
const string& key = it->first; // Cannot access memory for 'key'
assert(my_umap.size() >= 1); // This is failing
my_umap.erase(key);
}
}
我在 gdb 中运行代码,断言失败。当我查询 key
的值时,它说
cannot access memory
当我查询 my_umap
的大小时,它说大小为零。
如果 unordered_map 的大小为零,for 循环如何检测元素?没有其他线程访问此容器。我认为 unordered_map::insert()
将对象复制到容器中,所以被删除的原始对象应该无关紧要?
最佳答案
调用 my_umap.erase(...)
后,您的迭代器将失效:
References and iterators to the erased elements are invalidated. Other iterators and references are not invalidated.
这意味着一旦项目被删除,指向它的迭代器就不再有效。
你有几个选择:
1。使用迭代器删除,使用erase()
的返回值
自 C++11 起,通过迭代器删除将返回指向映射中下一项的迭代器。所以你可以使用它来保持你的迭代器有效:
auto it = my_umap.begin();
while (it != my_umap.end()) {
MyStruct& myStruct = it->second;
const bool deleteEntry = myStruct.ts.IsElapsed(std::chrono::seconds(5));
if(deleteEntry){
assert(my_umap.size() >= 1);
it = my_umap.erase(it); // <-- Return value should be a valid iterator.
}
else{
++it; // Have to manually increment.
}
}
2。将迭代器存储在列表对象中并在迭代后删除。
或者,您可以将删除候选对象存储在列表对象中(例如 vector 并在初始迭代后删除它们:
std::vector<MapType::iterator> deleteCandidates;
for(auto it = my_umap.begin(); it != my_umap.end(); ++it){
MyStruct& myStruct = it->second;
const bool deleteEntry = myStruct.ts.IsElapsed(std::chrono::seconds(5));
if(deleteEntry)
deleteCandidates.push_back(it);
}
for (auto it : deleteCandidates) {
my_umap.erase(it);
}
至于为什么你的断言失败,你可能遇到了访问无效迭代器的未定义行为,使你的 for
循环相信映射仍然不为空(因为 invalidIterator ! = my_umap.end()
).
关于c++ - unordered_map 元素被删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38854265/