【问题标题】:Does STL Vector use 'new' and 'delete' for memory allocation by default?STL Vector是否默认使用'new'和'delete'进行内存分配?
【发布时间】:2011-05-08 18:16:17
【问题描述】:

我正在为应用程序开发一个插件,其中的内存应该由应用程序分配并跟踪它。因此,应该以缓冲区的形式从主机应用程序获取内存句柄,然后将它们返回给应用程序。现在,我正计划使用 STL Vectors,我想知道它在内部使用了什么样的内存分配。

它是否在内部使用“新”和“删除”功能?如果是这样,我可以用自己的函数重载“新”和“删除”吗?或者我应该创建自己的模板分配器,这对我来说似乎是一项艰巨的工作,因为我在创建自定义模板方面没有那么丰富的经验。

欢迎任何建议/示例代码。可以像这样从应用程序中获取内存句柄

void* bufferH = NULL;

bufferH = MemReg()->New_Mem_Handle(size_of_buffer);
MemReg()->Dispose_Mem_Handle(bufferH); //Dispose it

【问题讨论】:

  • 要创建自己的分配器,请参阅 Matt Austern 的经典作品:drdobbs.com/184403759
  • @sbi:我还没有读过,但记得分配器语义在 C++11 中发生了显着变化。你确定经典在今天仍然适用吗? (这不是一个修辞问题,而是一个真实的问题。)
  • @einpoklum 这是 6 年前的评论。我们有两个新的标准版本,另一个即将推出。当然,从那以后情况可能会发生变化。

标签: c++ memory stl vector allocation


【解决方案1】:

vector默认使用std::allocator,需要std::allocator使用全局运算符new(即::operator new(size_t))来获取内存(20.4.1.1)。但是,每次调用 allocator::allocate 时不需要只调用一次。

所以是的,如果您替换全局运算符 new,那么 vector 将使用它,尽管不一定以真正允许您的实现“有效”管理内存的方式。原则上,您想使用的任何特殊技巧都可以通过 std::allocator 以 10MB 块获取内存并进行子分配完全无关紧要。

如果您有特定的实现,您可以查看其vector 的行为方式,如果您计划的分配策略本质上是特定于平台的,这可能就足够了。

【讨论】:

  • 不过,其他容器可以从自定义分配器中受益。对于某些应用程序,池分配器可以显着提高基于节点的容器的性能,例如 std::map
  • 小对象分配也是 Alexandrescu 最喜欢的话题之一——stackoverflow.com/questions/2707909/…
  • 感谢您的回复。我不应该使用“高效”这个词。我的意思是应用程序应该分配“所有”内存并跟踪它,无论它的大小或效率如何。但从您的评论来看,重载 new 和 delete 应该可以正常工作。
【解决方案2】:

STL 容器使用在构造时给定的分配器,default allocator 使用 operator newoperator delete

如果您发现默认设置不适合您,您可以提供符合容器要求的自定义分配器。引用了一些真实世界的例子here

我会首先使用默认值来衡量性能,并仅在您确实需要时进行优化。分配器抽象为您提供了一种相对干净的方式来微调这里而无需进行重大重新设计。你如何使用vector 对性能的影响可能远大于底层分配器(提前reserve(),避免在元素范围的中间插入和删除,有效地处理元素的复制构造 - 标准警告)。

【讨论】:

  • @James, @GMan:虽然有几个具体方面没有说明——特别是std::allocator 何时以及多久使用::operator new 来获取内存,以及如何(或者即使) 使用了hint 参数。
  • 感谢史蒂夫的回复。我确实提前保留了向量,并避免删除和插入中间范围的元素。但我不确定重载 new 和 delete 是否会使其使用主机应用程序分配的内存。对于使用“高效”这个词,我深表歉意。
  • 无需道歉,为更广泛的受众和您写作……您可能需要澄清内存所有权以获得最佳的具体答案。你打算存储什么,它的内存来自哪里,它是如何释放的?一个最小的示例代码会有所帮助。
  • @gutsblow - 如果这是您分配内存的唯一途径,那么我看不出如何避免编写自定义分配器来封装 host_new_handlehost_dispose_handle API。
  • 是的,但鉴于您是主机应用程序中的库,我不确定此类更改的范围 - 请参见此处:stackoverflow.com/questions/2007274/…。为什么不创建自己的分配器 - 一个包装 std::allocator 但在类级别重载 operator newoperator delete 的类模板?
【解决方案3】:

std::vector 使用unitialized_* 函数从原始内存构造其元素(使用placement new)。它使用创建它的任何分配器分配存储,默认情况下,该分配器直接使用::operator new(size_t)::operator delete(void *p)(即,不是特定类型的operator new)。

【讨论】:

    【解决方案4】:

    来自this 文章,“分配器的概念最初是为了为不同的内存模型提供抽象,以处理某些 16 位操作系统(例如近、远等)上具有不同指针类型的问题第四)" ...

    “标准提供了一个内部使用全局运算符‘new’和‘delete’的分配器”

    作者还指出,alocator 界面并没有那么可怕。正如 Neil Buchanan 所说,“自己试试吧!”

    【讨论】:

      【解决方案5】:

      实际的std::allocator 已针对相当大的尺寸对象进行了优化。在分配许多小对象时它不是最好的,对于许多大对象也不是最好的。话虽如此,它也不是为多线程应用程序编写的。

      我可以建议,在尝试编写自己的代码之前,如果您要使用多线程路由,请检查 Hoard 分配器。 (或者您也可以查看同样吸引人的 Intel TBB 页面。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-31
        • 1970-01-01
        • 2015-12-07
        • 2018-02-22
        • 2016-06-07
        • 1970-01-01
        • 2014-12-07
        相关资源
        最近更新 更多