C++标准库容器保证调用可替换的new函数吗?

22
如果我替换了所有我可以的operator new签名,至少在我测试过的实现中,我发现标准容器调用我的替换版本来分配内存。
这是否有标准保证?也就是说,使用优化版本而不调用我替换函数来使用标准容器底层内存,是否违法?

我相信在实践中是这样的。然而,我不太了解C++标准,无法引用它。 - Basile Starynkevitch
这个问题的背景是:std::vector<T>(使用默认分配器)是否可以使用realloccalloc而不是较弱的new API。当没有其他东西使用该虚拟地址空间时,new无法利用从操作系统获取已经清零的页面(避免memset(0))或扩展映射的能力。 - Peter Cordes
请注意,一些容器(特别是std::string)可能不会将所有元素存储在分配的内存中,而是可能将一些元素存储在容器对象本身中。请搜索“小字符串优化”以获取详细信息。 - MSalters
如果这个保证对你的程序很重要,即使可能会损失一些性能,你也可以选择自己分配内存并按照自己的方式进行存储,只在容器中存储指针。 - bartoli
@PeterCordes 我不认为这是可能的。即使全局 operator new 被替换了,std::vector<T> 仍然依赖于分配器接口来进行分配,而该接口并没有提供一种分配默认初始化数组或重新分配数据的方法 - 这些操作都是由 vector 自己完成的。理论上,std::vector<T> 可能会针对标准布局类型使用标准分配器进行专门优化,但我不认为有人会这样做。 - user1143634
@Ivan - 是的,分配器接口在这方面是有限制的,但当然一个实现可以实现一个增强的分配器接口来支持这个功能,并且如果检测到这些方法,则使用它们,否则回退到标准定义的方法(类似于您提到的为默认分配器专门化vector的想法,但可能更加通用)。当然,实现已经为可平凡复制类型专门化了容器行为的几个方面,所以这并不是不可能的,但我同意我认为还没有人这样做。 - BeeOnRope
2个回答

27

对于诸如std::vector<T>等支持自定义内存分配器的容器,默认分配器是std::allocator<T>。此类模板在标准的[section.default.allocator]中有所描述。根据C++14规范中的[allocator.members]/6:

通过调用::operator new(std::size_t)来获取内存

因此,需要替换的是全局operator new。如果您专门为T重载了operator new,默认分配器将不会使用该重载。


2
因此,即使在newmalloc兼容的平台上,除非库+编译器可以检测/证明未覆盖::operator new(std::size_t),否则std::vector实现实际上不能在底层使用calloc。 (在这种情况下,如果进行整个程序优化,则as-if规则应该允许它)。 "未指定何时以及如何调用new"的语言足以优化或合并某些分配,但不允许完全绕过new,对吗? - Peter Cordes
@PeterCordes 我非常有信心这是正确的解释。 - Brian Bi

7

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