Allocator
Raw allocation callbacks, allocation contracts, custom allocators, and out-of-memory handling.
std.allocator is the raw memory allocation layer used by owning standard
library types. Most code should prefer String, Array<T>, MemoryStream,
and other typed owners; use Allocator directly when an API needs explicit
storage control.
import {
Allocator,
AllocError
} from std.allocator;
An Allocator stores callbacks for allocation, reallocation, and freeing.
Allocator() uses the built-in process allocator. Allocator(alloc, realloc, free) lets tests and low-level code provide a custom strategy.
Allocator methods do not throw. alloc and realloc return null when memory
cannot be provided, and higher-level APIs convert that result into
AllocError.OutOfMemory.
Use std.arith helpers before calling an allocator when an allocation size is
computed from counts, element sizes, sentinels, or growth overhead. Allocation
wrappers should convert detected arithmetic overflow into
AllocError.OutOfMemory.
alloc(size, align) returns a raw pointer or null. alloc(0, align) returns
null. The caller owns any non-null pointer and must free it exactly once with
the same size and alignment contract.
import std.mem;
import {
Allocator,
AllocError
} from std.allocator;
fn main() {
let allocator = Allocator();
let ptr = allocator.alloc(4, 1);
if ptr == null {
throw AllocError.OutOfMemory;
}
defer allocator.free(ptr, 4, 1);
mem.set(ptr, 7 as u8, 4);
unsafe {
assert ptr[0] == 7 as u8;
}
}
realloc(ptr, old_size, new_size, align) resizes an allocation. Passing
null, 0 behaves like allocation, and new_size == 0 frees the allocation and
returns null. If growing or moving fails, the original pointer is still owned
by the caller.
Custom callbacks follow the same contract as the built-in allocator. Thread
safety is a property of the callbacks, not of the Allocator value.
fn my_alloc(size: usize, align: usize) -> *u8 { ... }
fn my_realloc(ptr: *u8, old_size: usize, new_size: usize, align: usize) -> *u8 { ... }
fn my_free(ptr: *u8, size: usize, align: usize) -> i32 { ... }
let allocator = Allocator(my_alloc, my_realloc, my_free);
Higher-level types accept Allocator values when their backing storage should
come from a specific allocator.
import {
Array
} from std.collections.array;
import {
String
} from std.string;
import {
Allocator
} from std.allocator;
fn main() {
let text = try String("hello", Allocator());
let values = Array<i32>(Allocator());
try values.append(10);
try values.append(32);
assert text.str() == "hello";
assert values.length == 2;
}
| Item | Signature | Purpose |
|---|---|---|
AllocError.OutOfMemory | error case | Allocation failed and callers should return or recover through normal error handling. |
Allocator() | constructor | Create an allocator backed by the built-in process allocator. |
Allocator(alloc, realloc, free) | constructor | Create an allocator from custom callbacks. |
alloc | alloc(size: usize, align: usize) -> *u8 | Allocate raw storage or return null. |
realloc | realloc(ptr: *u8, old_size: usize, new_size: usize, align: usize) -> *u8 | Resize raw storage or return null on failure. |
free | free(ptr: *u8, size: usize, align: usize) | Release an owned allocation. |
Fallible APIs should check for null and throw AllocError.OutOfMemory.