memory
|
There are, in general, three different ways and one special case to write a RawAllocator class. See the link for the exact requirements and behavior for each function.
Just go ahead and write a normal Allocator
class. It will work just fine and can be used anywhere a RawAllocator is required. Keep in mind, though, that the construct
or destroy
functions will not be called and its pointer typedefs not used.
This is the easiest way. The default specialization of allocator_traits will forward to member functions, if they exist, and has some fallback, if they don't. The following class overrides all the fallbacks:
There are fallbacks for every function except allocate_node()
and deallocate_node()
. A minimum class thus only needs to provide those two functions. The fallbacks "do the right thing", for example allocate_array()
forwards to allocate_node()
, is_stateful
is determined via std::is_empty
and max_node_size()
returns the maximum possible value.
Keep in mind that a RawAllocator has to be nothrow moveable and be valid to be used as a non-polymorphic base class, i.e. as a private
base to use EBO.
The full interface is provided by the allocator_storage typedefs. Other classes where this approach is used are heap_allocator or aligned_allocator. The latter also provides the full interface.
But sometimes it is not attractive to provide the full interface. An example is the library class memory_stack. Its interface consists of typical behaviors required for a stack, like unwinding, and it does not make sense to provide a deallocate_node()
function for it since there is no direct way to do so - only via unwinding.
In this case, the allocator_traits can be specialized for your type. Keep in mind that it is in the sub-namespace memory
of the namespace foonathan
. It needs to provide the following interface:
This approach is used in the mentioned memory_stack but also the memory_pool classes.
The allocator_traits provide a typedef allocator_type
. This type is the actual type used for the (de-)allocation and will be stored in all classes taking a RawAllocator. Its only requirement is that it is implicitly constructible from the actual type instantiated and that it is a RawAllocator.
The main use for this typedef is to support Allocator
classes. They need to be rebound to char
to allow byte-size allocations prior before they are actually used.
Using this technique otherwise is rather esoteric and I do not see any reason for it, but it is possible. Let there be a class raw_allocator
that is a RawAllocator, i.e. it provides the appropriate traits interface using any of the mentioned ways. This class also provides a constructor taking the class my_allocator
that wants to forward to it. Then you only need to write: