c++ - 当我只能覆盖新的和删除的时候,为什么我要为 STL 容器编写自定义分配器?

标签 c++ memory-management dynamic-memory-allocation c++20 allocator

我想写一个自定义的内存管理器/分配器来学习。我很想拥有一个主分配器,它从堆中请求 n 个字节的 ram(通过 new)。接下来是几个分配器……适配器?每个都将与 master 接口(interface),请求一个内存块来管理,这些将是堆栈、线性、池、slab 分配器等,每个分配器管理来自它们的 master 池分配器的分配。

我遇到的问题是我是否应该编写自定义 allocator_traits 来与各种 STL 容器进行交互;或者如果我应该忽略适配器的想法并简单地重载 new 和 delete 以使用自定义池分配器/管理器,主要的。

我有兴趣了解的是,为 STL 容器提供单独的分配器会给我带来哪些切实的好处?似乎默认的 std::allocator 会根据需要调用 new 和 delete,所以如果我重载它们而不是从我的大自定义内存池请求,我将获得所有好处,而无需自定义 std::allocator 代码。

或者这是某些类型的分配器模型的问题,比如对 std::deque 使用堆栈分配器会比默认分配器工作得更好吗?如果是这样,正常的 STL 实现是否已经为各种容器类型专门化了默认分配器,或者在对默认分配器的调用中进行了优化?

如果这很重要,我正在通过 GCC 10+ 使用 C++20

最佳答案

如果你想替换全局分配器,包括你正在使用的每个库,你不必使用 std::allocator

std 分配器可让您执行诸如创建临时分配池之类的操作。假设您有一些可以保证不会超过某个范围的数据结构,并且您知道(无论分配什么)90% 以上的部分将保留分配到范围的末尾。

一个相对简单的 std 分配器可以分发内存,从不回收它,并在范围末尾清理它,这比任何全局 newdelete 运算符都快得多.

只要您对容器的内容和生命周期模式有特殊了解,就可以为该特定容器手动调整分配器。标准分配器不能。有时当您愿意做出 std 容器不愿意做出的妥协时,您可以使用自定义分配器修补它们的行为。

std::deque 无法有效地使用堆栈分配器,因为它无法假定您主要将其用作堆栈。您可能主要将其用作队列。当你主要将它用作队列时,堆栈分配器将是一场灾难;但是如果你将它 90%+ 用作堆栈,堆栈分配器可以以适度的内存开销为代价更快(如果 99%+,堆栈分配器可以处理异常情况并清理非基于堆栈的操作).

最后,分配器可以让您区分不同类型的容器。您可能希望将文档(持久性)状态的内存分配到一个内存区域,并将“临时”非持久性数据分配到其他地方。

是的,您应该考虑不要使用标准分配器。优化是可替代的,在使系统的其余部分更高效和更实用后,您可以调整低级内存分配。只有当你有一些东西可以工作,但速度不够快,并且你已经确定新/删除是你无法设计的基本瓶颈时,你应该说“好的,是时候更换分配了!”

关于c++ - 当我只能覆盖新的和删除的时候,为什么我要为 STL 容器编写自定义分配器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64619312/

相关文章:

c++ - 从 OpenCV 中的 Matrix 访问值

C++17 使用模板参数推导指南继承 lambda 集

c - free() 在动态分配的内存中的作用域是什么?

c - 在 C 中使用 malloc() 或 realloc() 存储并打印数据

c++ - 模仿 "pointer to a reference"的类可以保存超出范围的变量吗?

c++ - -lboost_system 对 cygwin 上对 `boost::system::system_category()' 的 undefined reference 没有帮助

c++ - 如何在函数返回期间将 move 语义与 std::string 一起使用?

ios - 防止 UIWebView 无限期分配内存(NSURLCache 显然不起作用)

string - 为什么 Fortran 版本的 Delphi 的 TStringList 的业余实现比 Delphi 的内置版本低 10 倍?

Python H2O 内存管理