The following code snippet(see on godbolt) shows that big allocators won't increase the memory footprint of STL containers, but big comparators will. Why is it the case?
// 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;
}
Your allocator is not being used.
By default, std::set
receives std::allocator<int>
, but it needs to allocate some kind of nodes, not int
s. It uses std::allocator_traits::rebind
to get a different allocator for its internal node type.
Pre-C++20 std::allocator
has a rebind
member type, which you inherit, and which std::allocator_traits::rebind
finds. That rebind
points to std::allocator
, so that's what you get.
Starting from C++20, there's no rebind
in std::allocator
, so std::allocator_traits::rebind
falls back to directly modifying the first template parameter of your allocator, and since it's not a template, you get a compilation error.
A possible solution is to make your allocator a template, and to provide your own rebind
(which can be malformed, then the template parameter will be replaced automatically):
template <typename T>
struct MyAllocator : public std::allocator<T>
{
char dummy[1024];
struct rebind {}; // Malformed `rebind` to hide the inherited one, if any.
};
Then 1072
is printed for me.