简体   繁体   中英

Creating an idiomatic stack based allocator for std::unordered_map

I'm writing a custom allocator for unordered_map to allocate on the stack. I'm a bit lost on how to do this idiomatically: Should I pass the stack resource as pointer to the allocator or even define the byte array inside the allocator? What is common practice here?

#include <memory>
#include <unordered_map>
#include <utility>
#include <limits>
#include <cstdio>
#include <string_view>
#include <array>

class some_stack_resource
{
    std::array<std::byte, 100> container_; // <-- how to allocate to this?
};

template <typename T>
class custom_allocator
{
public:
    using value_type = T;

    using pointer = T*;
    using const_pointer = const T*;

    using void_pointer = void*;
    using const_void_pointer = const void*;

    using size_type = size_t;
    using difference_type = std::ptrdiff_t;

    template <typename U>
    struct rebind
    {
        using other = custom_allocator<U>;
    };

    custom_allocator() noexcept {
        printf("Default constructed\n");
    }

    template <typename U>
    custom_allocator(const custom_allocator<U>& other) noexcept {
        printf("Copy constructed\n");

    }

    ~custom_allocator() {
        printf("Destructed\n");
    }

    pointer allocate(size_type numObjects, const_void_pointer hint) {
        return allocate(numObjects);
    }

    pointer allocate(size_type numObjects) {
        printf("allocate %zu\n", numObjects);
        return static_cast<pointer>(operator new(sizeof(T) * numObjects));
    }

    void deallocate(pointer p, size_type numObjects) {
        printf("deallocate %zu\n", numObjects);
        operator delete(p);
    }

    size_type max_size() const {
        return std::numeric_limits<size_type>::max();
    }

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

int main()
{
    some_stack_resource res; // <-- where to pass res idiomatically?

    using Key = std::string_view;
    using T = int;
    std::unordered_map<Key, T, std::hash<Key>, std::equal_to<Key>, custom_allocator<std::pair<const Key, T>>> m{ {"hello", 2} };
}

here is a good example of a short allocator Hinnant's short_alloc and based on it you can see how to 'hide' some_stack_resource inside custom_allocator from users. As a user of your code I wont create an extra entity some_stack_resource res; because it doesn't make code clean.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM