# How to Use mulle_allocator in Library Code vs Application Code: Best Practices

> Discover best practices for using mulle_allocator in library vs application code. Learn to manage allocators effectively for optimal performance and flexibility.

- Repository: [mulle-c/mulle-allocator](https://github.com/mulle-c/mulle-allocator)
- Tags: best-practices
- Published: 2026-03-07

---

**Library code should expose `struct mulle_allocator *` parameters or embed the allocator in data structures, while application code can rely on default convenience wrappers like `mulle_malloc` or install a custom global allocator.**

The `mulle_allocator` library from the mulle-c project provides a flexible, interchangeable memory management layer for C programs. Whether you are building reusable libraries or standalone applications, understanding how to use `mulle_allocator` correctly ensures proper decoupling from the C standard library and supports custom allocation schemes. This guide explains the recommended patterns based on the actual implementation in `mulle-c/mulle-allocator`.

## Library Code: Keep the Allocator Explicit

Library authors must avoid hardcoding dependencies on `malloc` and `free`. Instead, expose the allocator through your API to let callers provide custom allocation schemes such as shared memory, test allocators, or ABA-safe allocators.

### Pattern 1: Embed the Allocator in Data Structures

When the allocation strategy remains constant for the lifetime of an object, store the `struct mulle_allocator *` pointer inside your data structure. This approach, shown in the README at lines 60-90, eliminates the need to pass the allocator to every subsequent operation.

```c
struct my_object {
    struct mulle_allocator *allocator;
    int                     data;
};

struct my_object *my_object_alloc(struct mulle_allocator *allocator)
{
    struct my_object *obj = mulle_allocator_malloc(allocator, sizeof(*obj));
    obj->allocator = allocator;
    return obj;
}

void my_object_free(struct my_object *obj)
{
    mulle_allocator_free(obj->allocator, obj);
}

```

Embedding decouples the library from the C stdlib while reducing API surface area for allocation operations.

### Pattern 2: Pass the Allocator as a Parameter

For maximum flexibility, require callers to pass the allocator to every function that allocates or frees memory. As documented in the README at lines 95-124, this pattern prevents storage overhead but risks mismatched allocators if the caller passes a different allocator than the one used for allocation.

```c
void *my_library_alloc(struct mulle_allocator *allocator, size_t size)
{
    return mulle_allocator_malloc(allocator, size);
}

void my_library_free(struct mulle_allocator *allocator, void *ptr)
{
    mulle_allocator_free(allocator, ptr);
}

```

Both patterns are valid; choose embedding when the allocator stays constant, and passing when allocation strategies might vary per operation.

## Application Code: Use Defaults or Set a Global Allocator

Application developers benefit from simplified memory management through convenience wrappers or global configuration, without needing to thread allocators through every function call.

### Convenience Wrappers

For most programs, use the convenience wrappers defined in [`src/mulle-allocator.h`](https://github.com/mulle-c/mulle-allocator/blob/main/src/mulle-allocator.h) at lines 75-78. These functions internally use `mulle_default_allocator`, abstracting away the explicit allocator parameter.

```c
char *s = mulle_strdup("hello");
void *buf = mulle_malloc(1024);
void *zeroed = mulle_calloc(10, sizeof(int));
mulle_free(buf);

```

### Custom Global Allocators

If your application requires a different allocation strategy—such as `mulle_stdlib_allocator`, a test allocator, or an ABA-safe allocator—you have two options:

1. **Replace the global pointer**: Set `mulle_default_allocator` to your custom instance before any allocations occur.
2. **Pass explicitly to libraries**: Supply a custom allocator to library functions that accept it, or pass `NULL` to use the default.

```c
// Use standard library allocator explicitly
struct my_object *obj = my_library_create(&mulle_stdlib_allocator, args);

// Or use default (NULL means use mulle_default_allocator)
struct my_object *obj2 = my_library_create(NULL, args);

```

### Memory Failure Handling

Application code does not need to check for `NULL` return values. According to the source code in [`src/mulle-allocator.h`](https://github.com/mulle-c/mulle-allocator/blob/main/src/mulle-allocator.h), the allocator's failure handler aborts on out-of-memory conditions, terminating the program with a diagnostic instead of returning NULL.

## Summary

- **Library authors** should expose `struct mulle_allocator *` in their APIs, either embedding it in data structures (preferred for constant allocators) or passing it to every allocation function.
- **Application developers** can use convenience wrappers like `mulle_malloc` and `mulle_free`, which automatically use `mulle_default_allocator`.
- **Custom allocation schemes** are supported by either replacing the global `mulle_default_allocator` pointer or passing custom allocators explicitly to library functions.
- **No NULL checks are required** in application code because the allocator aborts on OOM failures.

## Frequently Asked Questions

### Should I check for NULL returns when using mulle_allocator?

No. The allocator's failure handler aborts the program on out-of-memory conditions rather than returning NULL. This design eliminates the need for defensive NULL checks in application code and ensures immediate failure with diagnostic information.

### Is it better to embed the allocator or pass it every time?

Embedding the allocator in your data structure (as shown in README lines 60-90) is preferred when the allocation strategy remains constant for the object's lifetime. Passing the allocator to every function (README lines 95-124) offers more flexibility but increases the risk of allocator mismatches if callers are inconsistent.

### How do I use a custom allocator without modifying library code?

Replace the global pointer `mulle_default_allocator` with your custom allocator instance at program startup. All subsequent calls to convenience wrappers like `mulle_malloc` will use your custom implementation. Alternatively, pass your custom allocator explicitly to library functions that accept a `struct mulle_allocator *` parameter.

### What files define the allocator structure and global instances?

[`src/mulle-allocator-struct.h`](https://github.com/mulle-c/mulle-allocator/blob/main/src/mulle-allocator-struct.h) defines the `struct mulle_allocator` layout that you embed or pass around, while [`src/mulle-allocator.h`](https://github.com/mulle-c/mulle-allocator/blob/main/src/mulle-allocator.h) declares the global allocator instances including `mulle_default_allocator`, `mulle_stdlib_allocator`, and `mulle_stdlib_nofree_allocator`, along with the public convenience API.