foonathan / memory

STL compatible C++ memory allocator library using a new RawAllocator concept that is similar to an Allocator but easier to use and write.
https://memory.foonathan.net
zlib License
1.5k stars 194 forks source link

Wrapping Stateful to Stateless allocators #141

Closed kevin-- closed 2 years ago

kevin-- commented 2 years ago

Hello, I'm in a bit of a bind where I need to use a boost::icl::split_interval_map with some custom allocators. The ICL library has not been updated in some time, so does not support the new C++11 style of allocators which may be stateful.

My planned work around is to create a stateless allocator which can attach itself to the thread-local or global pre allocated RawAllocator in the constructor.

Roughly:

using MemPool = foonathan::memory::memory_pool<...etc>;
MemPool globalInstance;
....
template<typename T>
using StdWrapper = foonathan::memory::std_allocator<T, MemPool>;

template <typename T>
class StatelessAllocator
{
public:
    using NestedAlloc = StdWrapper<T>;
    // boiler plate types, etc, or inherit from StdWrapper  

    StatelessAllocator()
    : mAlloc( foonathan::memory::make_std_allocator<T>( globalInstance ) )
    {
    }
     // pass thru methods    
    NestedAlloc mAlloc;
};

// fails to compile
boost::icl::split_interval_map<T, U, StatelessAllocator<pair<T,U>> m;
// as does
std::list<T, StatelessAllocator<T>> l;

The failure occurs at this point

/// \effects Default constructs it by storing a default constructed, stateless \c RawAllocator inside the reference.
/// \requires The \c RawAllocator type is stateless, otherwise the body of this function will not compile.
std_allocator() noexcept : alloc_reference(allocator_type{})

which reading the documentation does make sense, but I'm not completely sure how I'm meant to bridge this gap to make my RawAllocator properly stateless as required by the default constructor, or if there's another work around I should try. Any advice would be appreciated. Thank you.

foonathan commented 2 years ago

Instead of trying to change std_allocator, I would recommend writing a stateless RawAllocator:

struct global_pool_allocator
{
    void* allocate_node(std::size_t size, std::size_t alignment)
    {
           return globalInstance.allocate(...);
    }

    void deallocate_node(void *node, std::size_t size, std::size_t alignment) noexcept { … }
};
kevin-- commented 2 years ago

nice one. works great. Thank you