【问题标题】:Does a std::map with default allocator initialised to be empty allocate memory?具有默认分配器初始化为空的 std::map 是否分配内存?
【发布时间】:2021-07-28 13:32:07
【问题描述】:

如果我有一个带有默认分配器的 std::map 初始化为无元素,当它被定义为提供一些容量时是否会分配内存?有没有办法在第一次执行插入之前阻止内存分配?我喜欢这种行为,因为我需要经常创建地图,但它通常根本不使用,因此没有插入任何元素。我想只在插入元素时支付内存分配的成本。

std::map<string, double> foo{}; // Is there memory allocation here?

【问题讨论】:

  • 答案取决于您使用的 STL。
  • 你确定一个空地图分配了什么?哪个编译器?
  • 我从未尝试过,但你的问题让我想知道:我该如何找到答案?我想我会尝试通过仅定义 allocate (应该“隐藏”基本实现)来继承 std::allocator,这样我就可以探测 when它被有效地调用...allocate 的定义只需将调用路由到基本实现)。要使用它,请将其作为std::map 的第四个参数传递(并将第三个设置为std::less&lt;std::string&gt;。那么你应该能够自己回答这个问题......;)
  • @Tenphase 也许最简单的方法是重新定义operator new;现场演示:godbolt.org/z/zK3Eoh3WK。使用我的 MSVC,它输出 40,支持 Artyer 的答案。
  • @DanielLangr 是的,但是您的解决方案很难在已经编写的代码中使用。除非您将std::map 子类化,这甚至会更复杂...通过在单个用户定义的allocator隐藏 allocate,您将能够探测任何特定的实例任何 STL 容器。因此,想法/提议... ;)

标签: c++


【解决方案1】:

可以在此处找到类似问题的更详细答案:https://stackoverflow.com/a/57299732/5754656


标准没有强制要求什么是空的/默认构造的地图。大多数都有其内部指针指向某个“结束节点”。在 libc++ 和 libstdc++ 中,这个端节点没有堆分配,默认构造函数标记为noexcept(并且没有分配,如你所愿)。在微软的标准库中,结束节点在堆上,会有内存分配。

如果不使用,防止内存分配的唯一方法是不调用默认构造函数。这可能意味着使用替代地图实现或使用std::optional&lt;std::map&gt; 或其他东西

【讨论】:

  • OT:这也有有趣的后果。当map的默认构造函数在Microsoft STL中分配时,这基本上意味着它的移动构造函数也不是noexcept(需要将map变为空=默认构造状态)。然后,一旦有了一个映射向量,这些映射就会在向量重新分配时复制。这不仅效率低下,而且不允许在包含在向量中的映射中包含不可复制的对象(例如std::vector&lt;std::map&lt;int, std::unique_ptr&lt;X&gt;&gt;&gt;)。关于这个问题,这里已经发布了几个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-04
相关资源
最近更新 更多