std::map 到 std::list 导致 SIGSEGV

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

我想在将 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;或者更好 - 不要使用单独的字符串,应用重复数据删除等。

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

如果你的记忆力如此有限以至于你不能同时拥有完整的地图和完整的列表,那么你只是使用了错误的数据结构——因为,就像我说的,这两个很浪费。尽管如此,如果你坚持,你可以重复插入 *differences_map.begin() 到列表中,然后从映射中删除它(并且每次在迭代器失效后再次获得 .begin())。

正如 yussuf 评论的那样,您可以在 找到解决方案。我已将其改编为我的示例。 (需要 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 或其他任何地方。然后,您可以廉价而轻松地复制它们,而无需复制底层数据。您仍然可以获得(或多或少)值语义,并且不需要手动管理对象生命周期。