自定义STL容器内存分配器需满足类型定义、allocate/deallocate实现及相等性比较等要求,通过继承或模板可实现如日志记录、内存池、共享内存等策略,提升性能或便于调试。

在C++中,STL容器(如std::vector、std::list、std::map等)都支持自定义内存分配器。通过替换默认的std::allocator,你可以控制容器的内存分配行为,比如使用内存池、共享内存或跟踪内存使用情况。
内存分配器的基本要求
要自定义STL容器的内存分配器,你的类需要满足一定标准。一个合法的分配器必须:
- 定义
value_type、pointer、const_pointer、reference、const_reference、size_type和difference_type - 提供
allocate(size_t n):分配未初始化的内存 - 提供
deallocate(pointer p, size_t n):释放内存 - 支持
construct和destroy(C++17前),或由容器自行处理对象构造/析构(C++17起) - 两个分配器实例必须能相互比较相等(通常状态无关)
实现一个简单的自定义分配器
下面是一个使用::operator new和::operator delete但带打印功能的简单分配器示例:
立即学习“C++免费学习笔记(深入)”;
template <typename T>
struct MyAllocator {
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;
<pre class='brush:php;toolbar:false;'>// 支持不同类型的再绑定
template<typename U>
struct rebind {
using other = MyAllocator<U>;
};
MyAllocator() = default;
template<typename U>
MyAllocator(const MyAllocator<U>&) {}
pointer allocate(size_type n) {
std::cout << "Allocating " << n << " elements of size " << sizeof(T) << std::endl;
return static_cast<pointer>(::operator new(n * sizeof(T)));
}
void deallocate(pointer p, size_type n) {
std::cout << "Deallocating " << n << " elements" << std::endl;
::operator delete(p);
}
// C++17 起 construct 和 destroy 不再强制要求
template<typename U, typename... Args>
void construct(U* p, Args&&... args) {
new(p) U(std::forward<Args>(args)...);
}
template<typename U>
void destroy(U* p) {
p->~U();
}
bool operator==(const MyAllocator&) const { return true; }
bool operator!=(const MyAllocator&) const { return false; }};
在STL容器中使用自定义分配器
将自定义分配器作为模板参数传入容器即可:
立即学习“C++免费学习笔记(深入)”;
// 使用自定义分配器的 vector std::vector<int, MyAllocator<int>> vec; <p>vec.push_back(10); vec.push_back(20); vec.push_back(30);</p><p>// 分配器会自动在扩容时被调用</p>
也可以为已有类型定义别名以简化使用:
using MyIntVector = std::vector<int, MyAllocator<int>>; MyIntVector v; v.push_back(42);
实际应用场景
自定义分配器常用于以下场景:
- 性能优化:使用内存池减少频繁调用系统分配器的开销
- 嵌入式系统:在固定内存区域中分配,避免堆碎片
- 共享内存:多个进程共享同一块内存中的容器数据
- 调试与监控:记录内存分配/释放,检测泄漏或异常模式
例如,结合内存池的分配器可以显著提升频繁增删元素的std::list性能。
基本上就这些。只要满足接口规范,你可以自由实现各种策略的分配器来适配具体需求。











