STL向量默认使用'new'和'delete'进行内存分配吗?

10

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

它是否内部使用 'new' 和 'delete' 函数?如果是,那么我可以重载 'new' 和 'delete' 函数吗?还是说我应该创建自己的模板分配器,但这对我来说可能有些困难,因为我在创建自定义模板方面经验不太丰富。

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

void* bufferH = NULL;

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

要创建自己的分配器,请参考Matt Austern的经典著作:http://www.drdobbs.com/184403759。 - sbi
@sbi:我还没有读过那个,但是记得在C++11中分配器语义发生了重大变化。你确定经典仍然适用于今天吗?这不是一个修辞问题,而是一个真正的问题。 - einpoklum
1
@einpoklum 那是一个6年前的评论。我们现在有两个新的标准版本,还有一个即将发布。当然,自那时以来可能已经发生了变化。 - sbi
5个回答

18
默认情况下,vector 使用 std::allocator,而std::allocator 必须使用全局操作符 new(即::operator new(size_t))来获取内存(参见20.4.1.1)。然而,并不需要每次调用 allocator::allocate时都调用它一次。

因此,如果您替换了全局操作符 new,则vector将使用它,虽然不一定以真正允许您的实现"高效地"管理内存的方式。您想要使用的任何特殊技巧理论上都可能被std::allocator以10MB块抓取内存并进行子分配的方式完全忽略。

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


1
其他容器也可以从自定义分配器中受益。对于某些应用程序,池分配器可以大大提高基于节点的容器(如std::map)的性能。 - James McNellis
1
小对象分配也是Alexandrescu最喜欢的话题之一 - http://stackoverflow.com/questions/2707909/how-do-i-use-lokis-small-object-allocator - Steve Townsend
谢谢回复。我不应该使用“高效”这个词。我的意思是,该应用程序应该分配“所有”内存并跟踪它,无论其大小或效率如何。但从您的评论中看来,重载new和delete应该可以正常工作。 - rwb

6

STL容器在构造时使用它们被给予的分配器,其中包括使用operator newoperator delete默认分配器

如果您发现默认选项不适用于您,可以提供符合容器要求的自定义分配器。这里有一些实际示例(点击此处)

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


@James,@GMan:有几个具体的方面是未指定的,特别是std::allocator何时以及多久使用::operator new来获取内存,以及如何(甚至是否)使用hint参数。 - Jerry Coffin
1
@gutsblow - 如果这是您唯一的分配内存的路径,那么我看不出您如何避免编写自定义分配器来封装host_new_handlehost_dispose_handle API。 - Steve Townsend
那么,如果用封装了host_new_handle和host_dispose_handle的函数重载'new'和'delete',这是否意味着STL也从这些函数中获取内存? - rwb
1
是的,但我不确定这样的更改范围,因为您是主机应用程序中的库-请参见此处:https://dev59.com/bEvSa4cB1Zd3GeqPcCQB。为什么不创建自己的分配器-一个类模板,它包装`std::allocator`,但在类级别上重载`operator newoperator delete`? - Steve Townsend
祝你好运 - 网上有很多模型,只需确保选择一个可行的跟随即可。 - Steve Townsend
显示剩余5条评论

3

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


2
这篇文章中,“分配器的概念最初是引入为不同内存模型提供抽象,以解决某些16位操作系统(如near、far等)上具有不同指针类型的问题”...
“标准提供了一个分配器,它在内部使用全局运算符'new'和'delete'”
作者还指出,分配器接口并不可怕。正如Neil Buchanan所说,“自己试试吧!”

2
实际上,std::allocator 已经针对相当大范围的大小对象进行了优化。它在分配许多小对象或许多大对象时并不是最佳选择。话虽如此,它也没有为多线程应用程序编写。
在尝试编写自己的分配器之前,我可以建议您如果您要使用多线程路线,请先查看Hoard分配器。(或者您也可以查看同样吸引人的Intel TBB页面。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接