为什么 C++11/Boost `unordered_map` 在擦除时不重新散列?

2024-05-03

我想知道为什么 C++11 和 Boost 的 hashmap 在通过迭代擦除元素时不会调整大小。即使这在技术上不是内存泄漏,我认为这可能是应用程序中的一个严重问题(这对我来说是一个隐藏的问题,很难追踪它),并且它实际上可能会影响许多应用程序。这是容器的“设计缺陷”吗?

我对它进行了基准测试,似乎影响了多个编译器版本(包括 VS、Clang、GCC)

重现该问题的代码是:

std::unordered_map<T1,T2> m;

for (int i = 0; i < 5000000; i++)
        m.insert(std::make_pair(i, new data_type));


for (map_type::iterator it = m.begin(); it != m.end();) {
        delete it->second;
        it = m.erase(it);
}   

我创建了一个独立测试 https://github.com/Darelbi/PublicProfileTests/blob/master/BoostMemoryUsage/UnorderedMap.cpp使用自定义分配器来跟踪内存使用情况的文件。

据我了解,其背后的原因是允许通过迭代擦除元素并保留有效的迭代器以不擦除元素。这似乎有点奇怪,因为插入元素可能会导致重新哈希,从而使迭代器无效。

但你可以直接破坏地图..

这就是我解决这个问题的方法(我将地图包装在智能指针内,当它为空时,我只需重新创建一个新的空地图,结果比重新散列更快,不知道为什么。)。

一般来说,任何使用的应用程序unordered_map因为缓存元素的容器可能会遇到这个问题(您可能想从缓存中删除元素,但通常没有人执行“缓存重置”)


据我所知,这种行为并不是要求不使迭代器无效的结果(std::unordered_map::rehash也不会使它们无效)而不是复杂性要求的结果std::unordered_map::erase,平均需要恒定时间。

我不能告诉你,为什么这样指定,但我可以告诉你,为什么这是正确的默认行为for me:

  1. 在许多应用程序中,我的哈希表的内容实际上是 无论如何,初始化后不变 - 所以这里我不在乎。
  2. 如果不是这种情况,至少元素的平均数量 或多或少保持相同(在一个数量级内)。 所以即使在某个时间点删除了很多对象,new 元素可能很快就会添加。在这种情况下,它 不会真正减少内存占用和开销 重新散列两次(一次在删除后,一次在添加新元素后)通常会超过我通过更紧凑的表可能获得的任何性能改进。
  3. 如果您无法控制启发式(就像通过修改插入元素时可以的那样),则擦除大量元素(例如通过过滤器函数)将因中间重新哈希而严重减慢max_load_factor).
    因此,最后,即使在重新散列实际上有益的情况下,我通常也可以做出更好的决定,即何时进行(例如通过重新散列或复制和交换)而不是通用启发式std::unordere_map could.

再说一次,这些观点对于我的典型用例来说是正确的,我并不声称它们对于其他人的软件来说普遍正确,或者它们是规范背后的动机unordered_map

有趣的是,VS2015和libstc++似乎实现rehash(0)不同*:

  • libstdc++ 实际上会收缩(重新分配)存储表的内存
  • VS2015 将减小表大小(也称为存储桶编号),但不会重新分配表。因此,即使在重新散列空哈希图之后,表的剩余内存也不会被返回。

显然,最小化内存占用的唯一可移植方法是复制和交换。

关于文档,我同意这可能应该在某处明确提及,但另一方面它是例如与文档一致std::vector::erase()。另外,我也不是 100% 确定,是否真的不可能编写一个至少有时在擦除时重新哈希而不违反要求的实现。


*)我从结果中推断出这一点bucket_count and getAllocatedBytes()来自您的分配器,而不是实际查看源代码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 C++11/Boost `unordered_map` 在擦除时不重新散列? 的相关文章

随机推荐

  • 如何将 Jinja 与 Twisted 一起使用?

    我正在计划使用 Python 与 Twisted Storm 和 Jinja 一起开发一个讨论软件 问题是 Jinja 不是为 Twisted 或异步套接字库而设计的 并且使用 Twisted 提供的性能是我不打算使用 Flask 的原因
  • 将 MyGeneration 与 Fluent NHibernate 结合使用

    我在这里找到了一个使用 MyGeneration 生成 NHibernate 代码的绝佳模板 http vucetica blogspot com 2009 01 nhibernate template for my Generation
  • 如何更改 GridView 内 ListViewItemPresenter 中的 SelectedBackground

    我在 SubSection 中有一个 Clickable Gridview
  • 如何重命名 Workbench 中的选项卡?

    当我创建新的查询选项卡时 它被命名为 SQL File 1 或类似名称 我想重命名它以更好地识别它们 是否可以 您可以使用命名查询选项卡来注册它们 File gt Save Script 我将发布我认为相关且易于实现的功能请求
  • HTML5:从存储的二进制字符串播放视频

    我正在尝试使用 FileReader readAsBinaryString Blob File 将视频文件的内容作为二进制字符串读取 如示例中所示http www html5rocks com en tutorials file dndfi
  • 更新写入 java 文本文件的对象

    将 Java 对象或列表写入文本文件是可以的 但我想知道如何更新或重写以前写入的对象而不再次写入对象 例如 假设有一个 java util List 有一组对象 然后将该列表写入文本文件 然后稍后该文件将被再次读取并从列表中获取所有对象 然
  • 如何在目标c中获取当前位置的纬度和经度

    我使用以下代码来获取当前位置 我添加了 corelocation 框架 void viewDidLoad super viewDidLoad locationManager CLLocationManager alloc init loca
  • ASP.NET 的电子邮件地址验证

    使用什么来验证 ASP NET 表单上的电子邮件地址 我想确保它不包含 XSS 漏洞 这是 ASP NET 1 1 ASP NET Web 表单上发布的任何脚本标记都会导致您的网站抛出未处理的异常 您可以使用 asp 正则表达式验证器来确认
  • 为 Keras 编写自定义数据生成器

    我将每个数据点存储在 npy 文件中 其中shape 1024 7 8 我想通过类似的方式将它们加载到 Keras 模型中ImageDataGenerator 所以我编写并尝试了不同的自定义生成器 但它们都不起作用 这是我改编的一个this
  • 正确别名向量

    我无法在其他地方找到答案 所以我想我只需要问这个 我正在尝试获取向量 其中存储 int 指针 的别名 如下所示 void conversion Engine ENGINES The Engine class has a vector of
  • 创建带小数秒的时间戳

    awk可以使用 strftime 函数生成时间戳 例如 awk BEGIN print strftime Y m d H M S 2019 03 26 08 50 42 但我需要一个带有小数秒的时间戳 最好是纳秒 gnu date可以用 N
  • 如何使用 swift 隐藏导航控制器中的后栏按钮

    在故事板 Xcode 6 iOS 8 和 swift 中 我在导航控制器中嵌入了 TableViewController 从对象库中 我拖放一个栏按钮项目作为后退按钮 它显示一个图标图像 当我单击该按钮时 我显示一个设置视图 我怎样才能隐藏
  • 集成共享同一个 MySQL 数据存储的 Django 和 Rails 应用程序的最佳方式是什么?

    我将在网络上与 Python 开发人员合作 应用 我将用 Ruby 构建其中的一部分 而他正在 将使用 Django 构建它的另一部分 我不太了解 姜戈 我集成这两部分的计划是简单地映射某个 URL Python 的路径前缀 例如 以 se
  • Android GLSurfaceView 具有可绘制背景

    我有一个带有可绘制对象作为背景的 GLSurfaceView 但是在没有 surfaceView setZOrderOnTop true 的情况下渲染时只有背景可见 我需要避免使用 setZOrderOnTop true 因为在 GLSur
  • 模型绑定到 MVC 中的列表

    我无法在服务器端检索简单的列表 有人能指出我正确的方向吗 public class TestList public string id get set public string name get set public string loc
  • 如何在 Xamarin.Forms 中强制使用浅色模式?

    我的应用程序的 UI 设计为在灯光模式下使用 但如果手机的默认主题是深色模式 我的应用程序也会切换到深色模式 并且 UI 看起来很垃圾 所以我想强制我的应用程序使用灯光模式 我怎样才能做到这一点 In my app xaml我使用的文件Us
  • __subclasses__ 没有显示任何内容

    我正在实现一个从适当的子类返回对象的函数 如果我搬家SubClass from base py 没有出现子类 subclasses 它们必须在同一个文件中吗 也许我从来没有直接导入subclass py对Python隐藏子类 我能做些什么
  • 使用类型作为参数 Typescript

    如何在 Typescript 中使用类型作为参数 type myType const passingType t Type gt const x t passingType myType 我收到 TS 错误 t 指的是一个值 但在这里被用作
  • 在 jqgrid 的 0 行上,我们如何将 NaN 的第 1 页替换为其他内容?

    如果 jqgrid 在某个时间没有行 它会显示Page 1 of NaN什么是Nan这里 我们不能把它改成更合适的东西吗Page 0 of 0或者更好的东西 我的 jqgrid 代码 var grid jQuery list1 grid j
  • 为什么 C++11/Boost `unordered_map` 在擦除时不重新散列?

    我想知道为什么 C 11 和 Boost 的 hashmap 在通过迭代擦除元素时不会调整大小 即使这在技术上不是内存泄漏 我认为这可能是应用程序中的一个严重问题 这对我来说是一个隐藏的问题 很难追踪它 并且它实际上可能会影响许多应用程序