自定义内存分配器通过预分配内存池提升性能,适用于高频小对象分配场景。

在C++中,自定义内存分配器可以提升性能、减少碎片或满足特定硬件需求。标准库中的容器(如std::vector、std::list)都支持通过模板参数传入自定义分配器。实现一个自定义分配器需要遵循一定的接口规范,并重载关键操作。
内存分配器的基本结构
一个符合标准的C++内存分配器需定义以下类型和方法:
- value_type:被分配对象的类型
- pointer:指向value_type的指针
- const_pointer:常量指针
- reference:引用类型
- const_reference:常量引用
- size_type:大小类型(通常为std::size_t)
- difference_type:指针差值类型
- allocate():分配未初始化内存
- deallocate():释放已分配内存
- 构造与析构函数相关操作(construct/destroy,C++17后可省略)
注意:从C++17开始,construct和destroy不再是必需的,容器会使用std::allocator_traits来处理对象构造和销毁。
实现一个简单的池式分配器
下面是一个简化版的固定大小内存池分配器示例:
立即学习“C++免费学习笔记(深入)”;
templateclass PoolAllocator { public: using value_type = T; using pointer = T*; using const_pointer = const T*; using reference = T&; using const_reference = const T&; using size_type = std::size_t; using difference_type = std::ptrdiff_t; template struct rebind { using other = PoolAllocator; }; PoolAllocator() noexcept { pool = ::operator new(PoolSize * sizeof(T)); free_list = static_cast (pool); // 初始化空闲链表(简化处理) for (size_t i = 0; i < PoolSize - 1; ++i) { reinterpret_cast (free_list)[i] = &free_list[i + 1]; } reinterpret_cast (free_list)[PoolSize - 1] = nullptr; next = free_list; } ~PoolAllocator() noexcept { ::operator delete(pool); } template PoolAllocator(const PoolAllocator&) noexcept {} pointer allocate(size_type n) { if (n != 1 || next == nullptr) { throw std::bad_alloc(); } pointer result = static_cast (next); next = reinterpret_cast (next)[0]; return result; } void deallocate(pointer p, size_type n) noexcept { reinterpret_cast (p)[0] = next; next = p; } private: void* pool; T* free_list; T* next; };
在STL容器中使用自定义分配器
将上面的分配器用于std::vector:
#include#include int main() { std::vector > vec; vec.push_back(10); vec.push_back(20); vec.push_back(30); for (const auto& val : vec) { std::cout << val << " "; } std::cout << std::endl; return 0; }
该例子中,所有元素的内存都来自同一个预分配的内存池,避免了频繁调用系统new/delete,适合高频小对象分配场景。
注意事项与最佳实践
编写自定义分配器时应注意以下几点:
- 确保
allocate在无法满足请求时抛出std::bad_alloc - 不要在
deallocate中调用析构函数,只负责释放内存 - 多线程环境下需自行加锁保护共享资源
- 重绑定机制(rebind)要正确实现,以支持不同类型的转换
- 若用于生产环境,建议参考
std::pmr(C++17起)中的内存资源设计
基本上就这些。自定义分配器不复杂但容易忽略细节,尤其是生命周期管理和类型对齐问题。合理使用能显著优化特定场景下的内存行为。










