为什么 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` 在擦除时不重新散列? 的相关文章

  • C 编程 - 文件 - fwrite

    我有一个关于编程和文件的问题 while current NULL if current gt Id Doctor 0 current current gt next id doc current gt Id Doctor if curre
  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • “构建”构建我的项目,“构建解决方案”则不构建

    我刚刚开始使用VS2010 我有一个较大的解决方案 已从 VS2008 成功迁移 我已将一个名为 Test 的控制台应用程序项目添加到解决方案中 选择构建 gt 构建解决方案不编译新项目 选择构建 gt 构建测试确实构建了项目 在失败的情况
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • HTTPWebResponse 响应字符串被截断

    应用程序正在与 REST 服务通信 Fiddler 显示作为 Apps 响应传入的完整良好 XML 响应 该应用程序位于法属波利尼西亚 在新西兰也有一个相同的副本 因此主要嫌疑人似乎在编码 但我们已经检查过 但空手而归 查看流读取器的输出字
  • 不同枚举类型的范围和可转换性

    在什么条件下可以从一种枚举类型转换为另一种枚举类型 让我们考虑以下代码 include
  • 带动态元素的 WPF 启动屏幕。如何?

    我是 WPF 新手 我需要一些帮助 我有一个加载缓慢的 WPF 应用程序 因此我显示启动屏幕作为权宜之计 但是 我希望能够在每次运行时更改屏幕 并在文本区域中显示不同的引言 这是一个生产力应用程序 所以我将使用非愚蠢但激励性的引言 当然 如
  • 重载<<的返回值

    include
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • 如何将带有 IP 地址的连接字符串放入 web.config 文件中?

    我们当前在 web config 文件中使用以下连接字符串 add name DBConnectionString connectionString Data Source ourServer Initial Catalog ourDB P
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • IEnumreable 动态和 lambda

    我想在 a 上使用 lambda 表达式IEnumerable
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐

  • 如何将 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 在通过迭代擦除元素时不会调整大小 即使这在技术上不是内存泄漏 我认为这可能是应用程序中的一个严重问题 这对我来说是一个隐藏的问题 很难追踪它 并且它实际上可能会影响许多应用程序