Dynamic Memory Allocation#
- <mlib/alloc.h> (header file)#
Contains types, functions, and constants related to dynamic memory management.
C APIs#
Types#
-
struct mlib_allocator#
Provides support for customizing dynamic memory allocation.
- Header:
- Zero-initialized:
A zero-initialized
mlib_allocatoris not valid for any operation except withmlib_deallocate()of a null pointer.
Many
amongocAPIs accept anmlib_allocatorparameter, or otherwise consult other objects that carry anmlib_allocator(e.g.amongoc_loophas an associated allocator, and therefore any object associated with an event loop will also use that same allocator).-
mlib_allocator_impl const *impl#
Pointer to the allocator implementation.
-
struct mlib_allocator_impl#
Provides the backing implementation for an
mlib_allocator-
void *userdata#
Arbitrary pointer to context for the allocator.
- void *reallocate(
- void *userdata,
- void *[[nullable]] prev_ptr,
- size_t requested_size,
- size_t alignment,
- size_t previous_size,
- size_t *[[storage]] out_new_size,
(Function pointer member)
Note
Don’t call this directly. Use
mlib_allocate(),mlib_deallocate(), andmlib_reallocate()Implements custom allocation for the allocator. The user must provide a non-null pointer to a function for the allocator.
- Parameters:
userdata – The
mlib_allocator_impl::userdatapointer.prev_ptr – Pointer that was previously returned by
reallocate()requested_size – The requested amount of memory for the new region, or zero to request deallocation of
prev_ptr.alignment – The requested alignment of the new memory region. Must be a power of two.
previous_size – If
prev_ptris notnullptr, this is the previousrequested_sizeused whenprev_ptrwas allocated.out_new_size – An output parameter: The allocator will write the actually allocated size to this pointer. The argument may be
nullptr.
- Returns:
Upon success, must return a pointer to the newly allocated region of size at least
requested_sizewith alignment of at leastalignment.Upon failure, must return
nullptr.
Allocation Behavior
In brief:
If
requested_sizeis zero: Behave as-iffree(prev_ptr), set*out_new_sizeto zero.Otherwise, behave as-if
realloc(prev_ptr, requested_size), set*out_new_sizetorequested_size.
In greater detail, a user-provided allocation function must do the following:
If
prev_ptris null:If
requested_sizeis zero, return a null pointer.Attempt to allocate a region \(R\) of size \(S\) bytes, where \(S\) is at least
requested_size.If allocating \(R\) fails, return a null pointer.
If
out_new_sizeis not null, write \(S\) to*out_new_size.Return a pointer to the beginning of \(R\).
Otherwise (
prev_ptris non-null), let \(R_p\) be the existing memory region of size \(S_p\) pointed-to byprev_ptr.If
requested_sizeis zero:Release the region \(R_p\).
If
out_new_sizeis not null, write zero to*out_new_size.Return a null pointer.
Otherwise (
requested_sizeis non-zero), ifrequested_sizeis greater than \(S_p\):Attempt to grow the region \(R_p\) to a new size \(S\) where \(S\) is at least
requested_sizebytes. If successful:If
out_new_sizeis not null, write \(S\) to*out_new_size.Return a pointer to \(R_p\).
Otherwise (growing the region failed), attempt to allocate a new region \(R\) of size \(S\), where \(S\) is at least
requested_sizebytes. If succesful:Copy the first \(S_p\) bytes from \(R_p\) into \(R\).
Release the region \(R_p\).
If
out_new_sizeis not null, write \(S\) to*out_new_size.Return a pointer to the beginning of \(R\).
Otherwise (allocating a new region failed), return a null pointer. (Do not modify the region \(R_p\) nor write anything to
out_new_size)
Otherwise (
requested_sizeis non-zero and at most \(S_p\)):Optionally, to simply reuse the region \(R_p\):
If
out_new_sizeis not null, write \(S_p\) to*out_new_sizeReturn
prev_ptrunmodified.
Otherwise, attempt to shrink the region \(R_p\) to a new size \(S\) that is at least
requested_sizebytes. If successful:If
out_new_sizeis not null, write \(S\) to*out_new_size.Return a pointer to \(R_p\).
Otherwise (shrinking the region failed), attempt to allocate a new region \(R\) of size \(S\), where \(S\) is at least
requested_size. If succesful:Copy the first
requested_sizebytes from \(R_p\) into \(R\).If
out_new_sizeis not null, write \(S\) into*out_new_size.Release the region \(R_p\).
Return a pointer to the beginning of \(R\).
Otherwise (allocating a new region failed), return a null pointer (Do not modify the region \(R_p\) nor write anything to
out_new_size).
-
void *userdata#
Functions#
-
void *mlib_allocate(mlib_allocator alloc, size_t sz)#
-
void mlib_deallocate(mlib_allocator alloc, void *p, size_t sz)#
- void *mlib_reallocate(
- mlib_allocator alloc,
- void *prev_ptr,
- size_t sz,
- size_t alignment,
- size_t prev_size,
- size_t *out_new_size,
Attempt to allocate or deallocate memory using the allocator
alloc.- Parameters:
alloc – The allocator to be used.
p – (For deallocation) A pointer that was previously returned by
mlib_allocate()using the sameallocparameter.sz – For allocation, the requested size. For deallocation, this must be the original
szvalue that was used withmlib_allocate().
- Returns:
- Header:
The
mlib_reallocate()function is a wrapper around themlib_allocator_impl::reallocate()function.Important
For
mlib_deallocate(): If the pointerpis null, then it is legal forallocto have a nullmlib_allocator::implmember. This is the only legal use of a null allocator.This behavior is crafted specifically to support deletion of aggregate types which store an allocator and a pointer as a member, so that deleting a zero-initialized instance of that struct is a valid no-op.
Constants#
-
const mlib_allocator mlib_default_allocator#
A reasonable default
mlib_allocator.- Header:
This allocator is implemented in terms of the standard library
realloc()andfree()functions.
-
const mlib_allocator mlib_terminating_allocator#
A special
mlib_allocatorthat terminates the program if there is any attempt to allocate memory through it.- Header:
This allocator is intended to be used in places where the programmer wishes to assert that dynamic allocation will not occur. If an attempt is made to allocate memory using this alloator, then a diagnostic will be printed to standard error and
abort()will be called.
C++ APIs#
Types#
-
template<typename T = void>
class mlib::allocator# Provides a C++ allocator interface for an
mlib_allocator- Header:
This allocator type is not default-constructible: It must be constructed explicitly from an
mlib_allocator.-
using value_type = T#
-
using pointer = value_type*#
Types associated with this allocator.
Note
If
Tisvoid, then the allocator is a proto-allocator and must be converted to a typed allocator before it may be used.
-
allocator(mlib_allocator a)#
Convert from an
mlib_allocatora.
-
template<typename U>
allocator(allocator<U>)# Convert-construct from another allocator instance, rebinding the allocated type.
-
bool operator==(allocator) const#
Compare two allocators. Two
allocators are equal if themlib_allocator_impl::userdataandmlib_allocator_impl::reallocate()pointers are equal.
-
mlib_allocator c_allocator() const#
Obtain the
mlib_allocatorthat is used by thisallocator
-
pointer allocate(std::size_t n) const#
-
void deallocate(pointer p, std::size_t n) const#
The allocation/deallocation functions for the C++ allocator interface.
- Parameters:
n – The number of objects to be allocated/deallocated
p – Pointer to a previous region obtained from an equivalent
allocator
Calls
mlib_allocate()/mlib_deallocate()to perform the allocation.
-
template<typename ...Args>
pointer new_(Args&&...) const# -
void delete_(pointer p) const#
New/delete individual objects using the allocator.
-
template<typename ...Args>
void construct(pointer p, Args&&... args) const# Construct an object at
pwith uses-allocator construction. This will “inject” the allocator into objects that support construction using the same memory allocator. This allows the following to work properly:// An allocator to be used mlib::allocator<> a = get_some_allocator(); // A string type that uses an mlib allocator using string = std::basic_string<char, std::char_traits<char>, mlib::allocator<char>> // Construct a vector with our allocator std::vector<string, mlib::allocator<string>> strings{a}; // Append a new string strings.emplace_back("hello, world!"); // [note]
On the line marked
[note]we are emplace-constructing a string from a character array. This would not work if theconstruct()method was not available, as the vector would try to default-construct a newmlib::allocator, which is not allowed. In this example,emplace_backwill end up callingallocator::construct()for the string, which will inject the parent allocator into the string during construction.
-
template<typename Alloc, typename T>
class mlib::bind_allocator# Create an object with a bound allocator.
- Header:
This class type supports CTAD, and using CTAD is recommended. It will perfect-forward the bound object into the resulting
bind_allocatorwrapper.-
allocator_type get_allocator() const#
Return the allocate that was bound with this object
-
decltype(auto) operator()(auto&&...)#
Call the underlying invocable with the given arguments, if such a call is well-formed.
This method is cvref-overloaded for the underlying object.
-
auto query(auto q) const#
Apply a query to the underlying object. (See: Query Objects)
-
struct mlib::alloc_deleter#
A deleter type for use with
std::unique_ptrthat deletes an object using anmlib::allocator- Header:
-
template<typename T>
using mlib::unique_ptr = std::unique_ptr<T, alloc_deleter># A
std::unique_ptrtype that uses anmlib::allocator.- Header:
See also
Functions#
-
template<typename T>
unique_ptr<T> mlib::allocate_unique( - allocator<> a,
- auto&&... args,
Construct an
mlib::unique_ptr<T>using the given allocator to manage the object.- Header:
Constants#
-
const allocator<> mlib::terminating_allocator{::mlib_terminating_allocator}#
A C++ version of the
mlib_terminating_allocator- Header: