Creating Custom Allocators

To create a custom allocator, first declare and initialize a structure of type CFAllocatorContext. Initialize the version field to 0 and allocate and assign any desired data, such as control information, to the info field. The other fields of this structure are function pointers described in Implementing Allocator Callbacks, below.

Once you have assigned the proper values to the fields of the CFAllocatorContext structure, invoke the CFAllocatorCreate function to create the allocator object. The second parameter of this function is a pointer to the structure. The first parameter of this function identifies an allocator to use for allocating memory for the new object. If you want to use the allocate callback in the CFAllocateContext structure for this purpose, specify the kCFAllocatorUseContext constant for the first parameter. If you want to use the default allocator, specify NULL in this parameter.

Listing 1  Creating a custom allocator

static CFAllocatorRef myAllocator(void) {
    static CFAllocatorRef allocator = NULL;
    if (!allocator) {
        CFAllocatorContext context =
            {0, NULL, NULL, (void *)free, NULL,
             myAlloc, myRealloc, myDealloc, NULL};
        context.info = malloc(sizeof(int));
        allocator = CFAllocatorCreate(NULL, &context);
    }
    return allocator;
}

Implementing Allocator Callbacks

The CFAllocatorContext structure has seven fields defining callback functions. If you create a custom allocator you must implement at least the allocate function. Allocator callbacks should be thread-safe and, if the callback invokes other functions, they should be re-entrant as well.

The retain, release, and copy-description callbacks all take as their single argument the info field of the CFAllocatorContext structure. Typed as void *, this field points to any data that you define for the allocator, such as a structure containing control information.

Retain Callback:

const void *(*retain)(const void *info);

Retain the data you have defined for the allocator context in info. This might make sense only if the data is a Core Foundation object. You may set this function pointer to NULL.

Release Callback:

void (*release)(const void *info);

Release (or free) the data you have defined for the allocator context. You may set this function pointer to NULL, but doing so might result in memory leaks.

Copy Description Callback:

CFStringRef (*copyDescription)(const void *info);

Return a reference to a CFString that describes your allocator, particularly some characteristics of your user-defined data. You may set this function pointer to NULL, in which case Core Foundation will provide a rudimentary description.

Allocate Callback:

void *   (*allocate)(CFIndex size, CFOptionFlags hint, void *info);

Allocate a block of memory of at least size bytes and return a pointer to the start of the block. The hint argument is a bitfield that you should currently not use. The size parameter should always be greater than 0. If it is not, or if problems in allocation occur, return NULL. This callback may not be NULL.

Reallocate Callback:

void *   (*reallocate)(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info);

Change the size of the block of memory pointed to by ptr to the size specified by newsize and return the pointer to the larger block of memory. Return NULL on any reallocation failure, leaving the old block of memory untouched. Note that the ptr parameter will never be NULL, and newsize will always be greater than 0—this callback is not used unless those two conditions are met.

Leave the contents of the old block of memory unchanged up to the lesser of the new or old sizes. If the ptr parameter is not a block of memory that has been previously allocated by the allocator, the results are undefined; abnormal program termination can occur. The hint argument is a bitfield that you should currently not use. If you set this callback to NULL the CFAllocatorReallocate function returns NULL in most cases when it attempts to use this allocator.

Deallocate Callback:

void   (*deallocate)(void *ptr, void *info);

Make the block of memory pointed to by ptr available for subsequent reuse by the allocator but unavailable for continued use by the program. The ptr parameter cannot be NULL and if the ptr parameter is not a block of memory that has been previously allocated by the allocator, the results are undefined; abnormal program termination can occur. You can set this callback to NULL, in which case the CFAllocatorDeallocate function has no effect.

Preferred Size Callback:

CFIndex   (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);

Return the actual size the allocator is likely to allocate given a request for a block of memory of size size. The hint argument is a bitfield that you should currently not use.