C++ STL:为什么分配器不增加容器的内存占用?
C++ STL: Why allocators don't increase memory footprint of containers?
以下代码片段 (see on godbolt) 表明大型分配器不会增加 STL 容器的内存占用,但大型比较器会。为什么会这样?
// compiled with x86-64 gcc 10.3, -std=c++17
#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;
}
您的分配器未被使用。
默认情况下,std::set
接收std::allocator<int>
,但它需要分配某种节点,而不是int
。它使用 std::allocator_traits::rebind
为其内部节点类型获取不同的分配器。
Pre-C++20 std::allocator
有一个 rebind
成员类型,您继承它,std::allocator_traits::rebind
找到它。 rebind
指向 std::allocator
,所以这就是你得到的。
从 C++20 开始,std::allocator
中没有 rebind
,因此 std::allocator_traits::rebind
退回到直接修改分配器的第一个模板参数,并且由于它不是模板,你会得到一个编译错误。
一个可能的解决方案是让你的分配器成为一个模板,并提供你自己的rebind
(可能格式不正确,然后模板参数将被自动替换):
template <typename T>
struct MyAllocator : public std::allocator<T>
{
char dummy[1024];
struct rebind {}; // Malformed `rebind` to hide the inherited one, if any.
};
然后为我打印 1072
。
以下代码片段 (see on godbolt) 表明大型分配器不会增加 STL 容器的内存占用,但大型比较器会。为什么会这样?
// compiled with x86-64 gcc 10.3, -std=c++17
#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;
}
您的分配器未被使用。
默认情况下,std::set
接收std::allocator<int>
,但它需要分配某种节点,而不是int
。它使用 std::allocator_traits::rebind
为其内部节点类型获取不同的分配器。
Pre-C++20 std::allocator
有一个 rebind
成员类型,您继承它,std::allocator_traits::rebind
找到它。 rebind
指向 std::allocator
,所以这就是你得到的。
从 C++20 开始,std::allocator
中没有 rebind
,因此 std::allocator_traits::rebind
退回到直接修改分配器的第一个模板参数,并且由于它不是模板,你会得到一个编译错误。
一个可能的解决方案是让你的分配器成为一个模板,并提供你自己的rebind
(可能格式不正确,然后模板参数将被自动替换):
template <typename T>
struct MyAllocator : public std::allocator<T>
{
char dummy[1024];
struct rebind {}; // Malformed `rebind` to hide the inherited one, if any.
};
然后为我打印 1072
。