std::map to std::list leads to SIGSEGV

std::map to std::list leads to SIGSEGV

本文关键字:std to SIGSEGV leads list map      更新时间:2023-10-16

我想在将 std::map 转换为 std::list 时节省 RAM。因此,我必须删除两者之间的每个元素。但我得到了一个SIGSEGV。

template <class U>
auto ConvertFlatSegmentsMapToList(std::map<std::string /* relative_path */, U>& differences_map, std::list<U>& differences_list) -> void {
for (auto& i:differences_map) {
differences_list.push_back(i.second);
// differences_map.erase(i.first);//TODO: SIGSEGV
}
}

怎么做?

如果要节省内存,请不要使用std::map,也不要使用std::list- 使用std::vector; 或者更好的是 - 不要使用单独的字符串,应用重复数据删除等。

话虽如此,并回答您的问题:从映射中删除元素会使映射中的迭代器无效 - 并且 ranged-for 循环实际上基于迭代器。所以 - 你不能在你的循环期间删除。循环后使用differences_map.clear()。您还应该注意,单个元素删除在时间上比清除整个地图要昂贵得多。

如果你的内存非常有限,以至于你不能同时拥有完整的地图和完整的列表,那么你只是使用了错误的数据结构 - 因为,就像我说的,这两者都是相当浪费的。不过,如果你坚持,你可以反复将*differences_map.begin()插入到列表中,然后将其从映射中删除(每次在迭代器失效后再次获取.begin()(。

正如优素福评论的那样,您可以在 https://stackoverflow.com/a/8234813/1142788 找到解决方案。我已经将其改编为我的例子。(需要 C++11 支持(

template <class U>
auto ConvertFlatSegmentsMapToList(std::map<std::string /* relative_path */, U>& differences_map, std::list<U>& differences_list) -> void {
std::clog << "differences_map: " << differences_map.size() << std::endl;    // e.g. 6
std::clog << "differences_list: " << differences_list.size() << std::endl;  // e.g. 0
for (auto i = differences_map.cbegin(); i != differences_map.cend(); i = differences_map.erase(i)) {
differences_list.push_back(i->second);
}
std::clog << "differences_map: " << differences_map.size() << std::endl;    // e.g. 0
std::clog << "differences_list: " << differences_list.size() << std::endl;  // e.g. 6
}

你可以考虑将std::shared_ptr存储在你的maplist或其他什么。 然后,您可以廉价且轻松地复制它们,而无需复制基础数据。 您仍然可以获得(或多或少(值语义,并且不需要手动管理对象生存期。