Search code examples
c++stlallocator

C++ STL: Why allocators don't increase memory footprint of containers?


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;
}


Solution

  • Your allocator is not being used.

    By default, std::set receives std::allocator<int>, but it needs to allocate some kind of nodes, not ints. 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.