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

Posted

技术标签:

【中文标题】std::map 到 std::list 导致 SIGSEGV【英文标题】:std::map to std::list leads to SIGSEGV 【发布时间】:2018-06-05 11:14:34 【问题描述】:

我想在将 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
    

怎么做?

【问题讨论】:

当我在 for 循环后清除时,我不保存 RAM。我希望我一个一个地复制并在其间删除以节省 RAM。 这应该有助于您在迭代时删除:***.com/a/8234813/1142788 @yussuf:谢谢。我添加了一个答案。 【参考方案1】:

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

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

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

【讨论】:

这不是我的问题的答案。在任何情况下都不能使用向量。我使用地图是因为我需要地图。但在那之后,我需要一些更小且可分类的东西。如果我有一个 100 MB 的地图并创建一个 100 MB 的列表,那么如果我不再需要该地图,这将浪费内存。 @B.A.Sylla:向量是可以排序的,我不确定你的意思。另外,实现地图的方法不止一种。如果您的地图值很小,则std::map 的开销非常大。无论如何,当你 clear() 地图时,它会停止使用所有内存。 @einpoklum 太晚了!你已经复制了这一切。 @PaulSanders:所以? OP 并没有说没有足够的内存。 @PaulSanders:查看我的编辑。实际上,事后看来,这整件事都是一个 XY 问题,我们应该哄 OP 说出他真正想做的事情。【参考方案2】:

正如 yussuf 所说,您可以在 https://***.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::map::erase() 返回一个(有效的)迭代器?整洁。【参考方案3】:

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

【讨论】:

当速度比内存更重要时,这是正确的。指针需要内存。 @B.A.Sylla 不够重要,请参阅live demo here。

以上是关于std::map 到 std::list 导致 SIGSEGV的主要内容,如果未能解决你的问题,请参考以下文章

找到所有变位词

从嵌套在 std::map 中的 std::list 中删除元素的最佳方法

指向std :: vector和std :: list元素的指针

指向 std::vector 和 std::list 元素的指针

FJUTOJ-3682 LRU算法的实现2 (链表+哈希)

为啥允许 std::unordered_map::rehash() 使迭代器无效?