Calmarius
Calmarius

Reputation: 19431

Is it possible to write a custom STL allocator that uses pointers to allocation functions provided by the user?

We have a library that provides a C interface via extern "C", and is used from C code, but inside it uses STL containers and some C++ features like RAII for convenience.

Now there is a new requirement that the library should be able to take pointers to a custom malloc and free function coming from the client code, and use that for allocations inside. I can place them into the context structure of the library, and use them where needed, but using them with STL is puzzling...

I looked at allocator classes but it seems STL containers must be able to use the default constructors to create the allocator and it seems there is no way to place these pointers into them to let them call through them to do the allocations.

Is it possible to work this around preferably in a thread safe manner (without using globals)?

Upvotes: 2

Views: 466

Answers (3)

Jonathan Wakely
Jonathan Wakely

Reputation: 171263

I looked at allocator classes but it seems STL containers must be able to use the default constructors to create the allocator

That's not true, all containers can be constructed with an allocator explicitly, so you can create your allocator object and then pass it to the container.

extern "C"
{
  typedef void* (*allocation_function)(size_t);
  typedef void (*deallocation_function)(void*);
}

template<typename T>
class Allocator
{
public:
  typedef T value_type;

  Allocator(allocation_function alloc, deallocation_function dealloc)
  : m_allocate(alloc), m_deallocate(dealloc)
  { }

  template<typename U>
    Allocator(const Allocator<U>& a)
    : m_allocate(a.m_allocate), m_deallocate(a.m_deallocate)
    { }

  T* allocate(size_t n)
  { return static_cast<T*>(m_allocate(n * sizeof(T))); }

  void deallocate(T* p, size_t)
  { m_deallocate(p); }

private:
  template<typename U>
    friend class Allocator<U>;

  template<typename U>
    friend bool operator==(const Allocator<U>&, const Allocator<U>&);

  allocation_function   m_allocate;
  deallocation_function m_deallocate;
};

template<typename T>
bool operator==(const Allocator<T>& l, const Allocator<T>& r)
{ return l.m_allocate == r.m_allocate; }

template<typename T>
bool operator!=(const Allocator<T>& l, const Allocator<T>& r)
{ return !(l == r); }


Allocator<int> a(custom_malloc, custom_free);
std::vector<int, Allocator<int>> v(a);

If you're using not using C++11 yet then you need to provide a lot more members for your allocator to meet the old requirements, but the one above is OK for C++11. Using custom allocators in C++03 is difficult and not portable anyway, so you should aim to use a C++11 compiler if you need to do this.

Upvotes: 5

Yes. As an example, look into header gc/gc_allocator.h from Boehm garbage collector (you could easily replace the lower calls to GC_MALLOC etc by some function pointers). See this answer.

Upvotes: 0

randomusername
randomusername

Reputation: 8087

Since allocators cannot be state-full but must be default constructible, I would suggest using templates to instantiate the allocators at compile time.

Upvotes: -2

Related Questions