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_allocator
is not valid for any operation except withmlib_deallocate()
of a null pointer.
Many
amongoc
APIs accept anmlib_allocator
parameter, or otherwise consult other objects that carry anmlib_allocator
(e.g.amongoc_loop
has 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::userdata
pointer.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_ptr
is notnullptr
, this is the previousrequested_size
used whenprev_ptr
was 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_size
with alignment of at leastalignment
.Upon failure, must return
nullptr
.
Allocation Behavior
In brief:
If
requested_size
is zero: Behave as-iffree(prev_ptr)
, set*out_new_size
to zero.Otherwise, behave as-if
realloc(prev_ptr, requested_size)
, set*out_new_size
torequested_size
.
In greater detail, a user-provided allocation function must do the following:
If
prev_ptr
is null:If
requested_size
is 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_size
is not null, write \(S\) to*out_new_size
.Return a pointer to the beginning of \(R\).
Otherwise (
prev_ptr
is non-null), let \(R_p\) be the existing memory region of size \(S_p\) pointed-to byprev_ptr
.If
requested_size
is zero:Release the region \(R_p\).
If
out_new_size
is not null, write zero to*out_new_size
.Return a null pointer.
Otherwise (
requested_size
is non-zero), ifrequested_size
is greater than \(S_p\):Attempt to grow the region \(R_p\) to a new size \(S\) where \(S\) is at least
requested_size
bytes. If successful:If
out_new_size
is 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_size
bytes. If succesful:Copy the first \(S_p\) bytes from \(R_p\) into \(R\).
Release the region \(R_p\).
If
out_new_size
is 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_size
is non-zero and at most \(S_p\)):Optionally, to simply reuse the region \(R_p\):
If
out_new_size
is not null, write \(S_p\) to*out_new_size
Return
prev_ptr
unmodified.
Otherwise, attempt to shrink the region \(R_p\) to a new size \(S\) that is at least
requested_size
bytes. If successful:If
out_new_size
is 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_size
bytes from \(R_p\) into \(R\).If
out_new_size
is 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 samealloc
parameter.sz – For allocation, the requested size. For deallocation, this must be the original
sz
value 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 pointerp
is null, then it is legal foralloc
to have a nullmlib_allocator::impl
member. 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_allocator
that 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
T
isvoid
, 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_allocator
a
.
-
template<typename U>
allocator(allocator<U>)# Convert-construct from another allocator instance, rebinding the allocated type.
-
bool operator==(allocator) const#
Compare two allocators. Two
allocator
s are equal if themlib_allocator_impl::userdata
andmlib_allocator_impl::reallocate()
pointers are equal.
-
mlib_allocator c_allocator() const#
Obtain the
mlib_allocator
that 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
p
with 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_back
will 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_allocator
wrapper.-
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_ptr
that deletes an object using anmlib::allocator
- Header:
-
template<typename T>
using mlib::unique_ptr = std::unique_ptr<T, alloc_deleter># A
std::unique_ptr
type 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: