Module std.experimental.allocator
High-level interface for allocators. Implements bundled allocation/creation
and destruction/deallocation of data including structs and classes,
and also array primitives related to allocation. This module is the entry point
for both making use of allocators and for their documentation.
| Category | Functions | 
|---|---|
| Make | makemakeArraymakeMultidimensionalArray | 
| Dispose | disposedisposeMultidimensionalArray | 
| Modify | expandArrayshrinkArray | 
| Global | processAllocatortheAllocator | 
| Class interface | allocatorObjectCAllocatorImplIAllocator | 
Synopsis
// Allocate an int, initialize it with 42
int* p = theAllocatorLayered Structure
D's allocators have a layered structure in both implementation and documentation:
- A high-level, dynamically-typed layer (described further down in this
module). It consists of an interface called IAllocator, which concrete allocators need to implement. The interface primitives themselves are oblivious to the type of the objects being allocated; they only deal invoid[], by necessity of the interface being dynamic (as opposed to type-parameterized). Each thread has a current allocator it uses by default, which is a thread-local variabletheAllocatorof typeIAllocator. The process has a global allocator calledprocessAllocator, also of typeIAllocator. When a new thread is created,processAllocatoris copied intotheAllocator. An application can change the objects to which these references point. By default, at application startup,processAllocatorrefers to an object that uses D's garbage collected heap. This layer also include high-level functions such asmakeanddisposethat comfortably allocate/create and respectively destroy/deallocate objects. This layer is all needed for most casual uses of allocation primitives.
- A mid-level, statically-typed layer for assembling several allocators into
one. It uses properties of the type of the objects being created to route
allocation requests to possibly specialized allocators. This layer is relatively
thin and implemented and documented in the stdmodule. It allows an interested user to e.g. use different allocators for arrays versus fixed-sized objects, to the end of better overall performance..experimental .allocator .typed 
- A low-level collection of highly generic heap building blocks— Lego-like pieces that can be used to assemble application-specific allocators. The real allocation smarts are occurring at this level. This layer is of interest to advanced applications that want to configure their own allocators. A good illustration of typical uses of these building blocks is modulestdwhich defines a collection of frequently- used preassembled allocator objects. The implementation and documentation entry point is.experimental .allocator .showcase std. By design, the primitives of the static interface have the same signatures as the.experimental .allocator .building_blocks IAllocatorprimitives but are for the most part optional and driven by static introspection. The parameterized classCAllocatorImploffers an immediate and useful means to package a static low-level allocator into an implementation ofIAllocator.
- Core allocator objects that interface with D's garbage collected heap
(std), the C.experimental .allocator .gc_allocator mallocfamily (std), and the OS (.experimental .allocator .mallocator std). Most custom allocators would ultimately obtain memory from one of these core allocators..experimental .allocator .mmap_allocator 
Idiomatic Use of std
As of this time, std is not integrated with D's
built-in operators that allocate memory, such as new, array literals, or
array concatenation operators. That means std is
opt-in
For casual creation and disposal of dynamically-allocated objects, use make, dispose, and the array-specific functions makeArray,
expandArray, and shrinkArray. These use by default D's garbage
collected heap, but open the application to better configuration options. These
primitives work either with theAllocator but also with any allocator obtained
by combining heap building blocks. For example:
void fun(size_t n)
{
    // Use the current allocator
    int[] a1 = theAllocatorTo experiment with alternative allocators, set theAllocator for the
current thread. For example, consider an application that allocates many 8-byte
objects. These are not well supported by the default allocator, so a
free list allocator would be recommended.
To install one in main, the application would use:
void main()
{
    import stdSaving the IAllocator Reference For Later Use
As with any global resource, setting theAllocator and processAllocator
should not be done often and casually. In particular, allocating memory with
one allocator and deallocating with another causes undefined behavior.
Typically, these variables are set during application initialization phase and
last through the application.
To avoid this, long-lived objects that need to perform allocations,
reallocations, and deallocations relatively often may want to store a reference
to the allocator object they use throughout their lifetime. Then, instead of
using theAllocator for internal allocation-related tasks, they'd use the
internally held reference. For example, consider a user-defined hash table:
struct HashTable
{
    private IAllocator allocator;
    this(size_t buckets, IAllocator allocator = theAllocator) {
        thisFollowing initialization, the HashTable object would consistently use its
allocator object for acquiring memory. Furthermore, setting
HashTable to point to a different allocator should be legal but
only if the object is empty; otherwise, the object wouldn't be able to
deallocate its existing state.
Using Allocators without IAllocator
Allocators assembled from the heap building blocks don't need to go through
IAllocator to be usable. They have the same primitives as IAllocator and
they work with make, makeArray, dispose etc. So it
suffice to create allocator objects wherever fit and use them appropriately:
void fun(size_t n)
{
    // Use a stack-installed allocator for up to 64KB
    StackFront!65536 myAllocator;
    int[] a2 = myAllocatorIn this case, myAllocator does not obey the IAllocator interface, but
implements its primitives so it can work with makeArray by means of duck
typing.
One important thing to note about this setup is that statically-typed assembled
allocators are almost always faster than allocators that go through
IAllocator. An important rule of thumb is: "assemble allocator first, adapt
to IAllocator after". A good allocator implements intricate logic by means of
template assembly, and gets wrapped with IAllocator (usually by means of
allocatorObject) only once, at client level.
Functions
| Name | Description | 
|---|---|
| 
									allocatorObject(a)
								 | Returns a dynamically-typed CAllocatorbuilt around a given statically-
typed allocatoraof typeA. Passing a pointer to the allocator
creates a dynamic allocator around the allocator pointed to by the pointer,
without attempting to copy or move it. Passing the allocator by value or
reference behaves as follows. | 
| 
									dispose(alloc, p)
								 | Destroys and then deallocates (using alloc) the object pointed to by a
pointer, the class object referred to by aclassorinterfacereference, or an entire array. It is assumed the respective entities had been
allocated with the same allocator. | 
| 
									disposeMultidimensionalArray(alloc, array)
								 | Destroys and then deallocates a multidimensional array, assuming it was created with makeMultidimensionalArray and the same allocator was used. | 
| 
									expandArray(alloc, array, delta)
								 | Grows arrayby appendingdeltamore elements. The needed memory is
allocated usingalloc. The extra elements added are either default-
initialized, filled with copies ofinit, or initialized with values
fetched fromrange. | 
| 
									make(alloc, args)
								 | Dynamically allocates (using alloc) and then creates in the memory
allocated an object of typeT, usingargs(if any) for its
initialization. Initialization occurs in the memory allocated and is otherwise
semantically the same asT(args).
(Note that usingalloccreates a pointer to an (empty) array
ofTs, not an array. To use an allocator to allocate and initialize an
array, useallocdescribed below.) | 
| 
									makeArray(alloc, length)
								 | Create an array of Twithlengthelements usingalloc. The array is either default-initialized, filled with copies ofinit, or initialized with values fetched fromrange. | 
| 
									makeMultidimensionalArray()
								 | Allocates a multidimensional array of elements of type T. | 
| 
									processAllocator()
								 | Gets/sets the allocator for the current process. This allocator must be used
for allocating memory shared across threads. Objects created using this
allocator can be cast to shared. | 
| 
									sharedAllocatorObject(a)
								 | Returns a dynamically-typed CSharedAllocatorbuilt around a given statically-
typed allocatoraof typeA. Passing a pointer to the allocator
creates a dynamic allocator around the allocator pointed to by the pointer,
without attempting to copy or move it. Passing the allocator by value or
reference behaves as follows. | 
| 
									shrinkArray(alloc, array, delta)
								 | Shrinks an array by deltaelements. | 
| 
									theAllocator()
								 | Gets/sets the allocator for the current thread. This is the default allocator
that should be used for allocating thread-local memory. For allocating memory
to be shared across threads, use processAllocator(below). By default,theAllocatorultimately fetches memory fromprocessAllocator, which
in turn uses the garbage collected heap. | 
Interfaces
| Name | Description | 
|---|---|
| 
									IAllocator
								 | Dynamic allocator interface. Code that defines allocators ultimately implements this interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations. | 
| 
									ISharedAllocator
								 | Dynamic shared allocator interface. Code that defines allocators shareable across threads ultimately implements this interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations. | 
Classes
| Name | Description | 
|---|---|
| 
									CAllocatorImpl
								 | Implementation of IAllocatorusingAllocator. This adapts a
statically-built allocator type toIAllocatorthat is directly usable by
non-templated code. | 
| 
									CSharedAllocatorImpl
								 | Implementation of ISharedAllocatorusingAllocator. This adapts a
statically-built, shareable across threads, allocator type toISharedAllocatorthat is directly usable by non-templated code. | 
Structs
| Name | Description | 
|---|---|
| 
									RCIAllocator
								 | A reference counted struct that wraps the dynamic allocator interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations. | 
| 
									RCISharedAllocator
								 | A reference counted struct that wraps the dynamic shared allocator interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations. |