You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ STL:为何分配器不会增加容器的内存占用,而比较器会?

为什么STL容器的比较器体积会影响容器大小,而分配器不会?

先看你给出的代码运行结果:

#include <functional>
#include <iostream>
#include <memory>
#include <set>

struct MyLess : public std::less<int> { char dummy[1024]; };
struct MyAllocator : public std::allocator<int> { char dummy[1024]; };

int main() {
    std::cout << sizeof(std::set<int, MyLess>) << std::endl; // prints 1064
    std::cout << sizeof(std::set<int, std::less<int>, MyAllocator>) << std::endl; // prints 48
    return 0;
}

这个差异其实是GCC的STL实现对比较器和分配器的存储策略不同,再加上分配器的rebind机制细节共同导致的,我给你拆解一下:

1. 比较器是容器实打实的成员变量

GCC里std::set底层靠红黑树(_Rb_tree)实现,红黑树会把比较器作为直接成员变量存在容器对象里。你写的MyLess虽然继承了空的std::less<int>,但加了1024字节的dummy数组,所以它本身就占1024字节(加上空类的对齐要求,最终刚好对齐到8字节边界)。这个大小会直接加到std::set原本的成员大小上(比如红黑树的根指针、节点计数这些,加起来大概40字节),1024+40=1064,正好是你看到的结果。

2. 分配器是基类,还因rebind机制“偷偷”用了空类

和比较器不一样,GCC的红黑树并没有把分配器当成员变量存,而是继承自rebind之后的节点分配器,这里用到了C++的空基类优化(EBO)——如果基类是空类,就不会额外占内存。

但这里有个容易忽略的点:你的MyAllocator只继承了std::allocator<int>,却没重写rebind模板。当红黑树需要为它的节点分配内存时,会通过allocator_traits调用分配器的rebind方法,而因为MyAllocator没自己定义rebind,就会用父类std::allocator<int>的版本,返回的是std::allocator<_Rb_tree_node<int>>——这可是个空类!

所以红黑树实际继承的是空类,空基类优化生效,自然不会增加容器的大小,std::set的大小还是原本的48字节。要是你把MyAllocator改成模板类,并重写rebind让它给节点类型返回带1024字节的分配器,那容器大小肯定会涨上去。

内容的提问来源于stack exchange,提问作者Leon Cruz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 23:23:12