Allocators

Among the operating-system services that Core Foundation abstracts is memory allocation. It uses allocators for this purpose. Allocators are opaque objects that allocate and deallocate memory for you. You never have to allocate, reallocate, or deallocate memory directly for Core Foundation objects—and rarely should you. You pass allocators into functions that create objects; these functions have “Create” embedded in their names. The creation functions use the allocators to allocate memory for the objects they create.

Core Foundation allows you to create your own custom allocators. Core Foundation also provides a system allocator and initially sets this allocator to be the default one for the current thread. (There is one default allocator per thread.)

Ownership Policy

Applications using Core Foundation constantly access and create and dispose of objects. In order to ensure that you do not leak memory, Core Foundation defines rules for getting and creating objects.

1. You own an object if you create it (either directly or by making a copy of another object.
2. You do not own an object iIf you get it from somewhere else. If you want to prevent it being disposed of, you must add yourself as an owner (using CFRetain).
3. If you are an owner of an object, you must relinquish ownership when you have finished using it (using CFRelease).

If a function name contains the word "Create" or "Copy", you own the object. If a function name contains the word "Get", you do not own the object.

The Create Rule

Core Foundation functions have names that indicate when you own a returned object:
- Object-creation functions that have “Create” embedded in the name;
- Object-duplication functions that have “Copy” embedded in the name.

If you own an object, it is your responsibility to relinquish ownership (using CFRelease) when you have finished with it.

The Get Rule

If you receive an object from any Core Foundation function other than a creation or copy function—such as a Get function—you do not own it and cannot be certain of the object’s life span.

If you want to ensure that such an object is not disposed of while you are using it, you must claim ownership (with the CFRetain function). You are then responsible for relinquishing ownership when you have finished with it.

Instance Variables and Passing Parameters

A corollary of the basic rules is that when you pass an object to another object (as a function parameter), you should expect that the receiver will take ownership of the passed object if it needs to maintain it.

Core Foundation Object Life Cycle Management

The life span of a Core Foundation object is determined by its reference count—an internal count of the number of clients who want the object to persist. When you create or copy an object in Core Foundation, its reference count is set to one. Subsequent clients can claim ownership of the object by calling CFRetain which increments the reference count. Later, when you have no more use for the object, you call CFRelease. When the reference count reaches 0, the object’s allocator deallocates the object’s memory.

To increment the reference count of a Core Foundation object, pass a reference to that object as the parameter of the CFRetain function.
myString is a CFStringRef received from elsewhere:
myString = (CFStringRef)CFRetain(myString);

To decrement the reference count of a Core Foundation object, pass a reference to that object as the parameter of the CFRelease function:
CFRelease(myString);

Copy Functions

In general, a standard copy operation, which might also be called simple assignment, occurs when you use the = operator to assign the value of one variable to another. The expression myInt2 = myInt1, for example, causes the integer contents of myInt1 to be copied from the memory used by myInt1 into the memory used by myInt2. Following the copy operation, two separate areas of memory contain the same value. However, if you attempt to copy a Core Foundation object in this way, be aware that you will not duplicate the object itself, only the reference to the object.

If you want to duplicate an object, you must use one of the functions provided by Core Foundation specifically for this purpose. Continuing with the CFString example, you would use CFStringCreateCopy to create an entirely new CFString object containing the same data as the original.

Byte Ordering

Microprocessor architectures commonly use two different methods to store the individual bytes of multibyte numerical data in memory. This difference is referred to as “byte ordering” or “endian nature.” Most of the time the endian format of your computer can be safely ignored, but in certain circumstances it becomes critically important.

Explanation of big-endian (physical memory is organized with the address of each byte increasing from most significant to least significant) and little-endian byte ordering (the opposite: least significant first). 

Using Allocators in Creation Functions

Each Core Foundation opaque type has one or more creation functions, functions that create and return an object of that type initialized in a particular way. All creation functions take as their first parameter a reference to an allocator object (CFAllocatorRef).

You can pass the constant kCFAllocatorSystemDefault; this specifies the generic system allocator (which is the initial default allocator).

You can pass NULL to specify the current default allocator (which might be a custom allocator or the generic system allocator). This is the same as passing kCFAllocatorDefault.

Using the Allocator Context

Every allocator in Core Foundation has a context. A context is a structure that defines the operating environment for an object and typically consists of function pointers. The context for allocators is defined by the CFAllocatorContext structure. In addition to function pointers, the structure contains fields for a version number and for user-defined data.

typedef struct {  
  CFIndex version; void * info;
  const void *(*retain)(const void *info);
  void (*release)(const void *info);
  CFStringRef (*copyDescription)(const void *info);
  void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info);
  void * (*reallocate)(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info);
  void (*deallocate)(void *ptr, void *info);
  CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);
} CFAllocatorContext;

Getting the allocator context and user-defined data:

static int numOutstandingAllocations(CFAllocatorRef alloc) {  
  Context CFAllocatorContext context;
  context.version = 0;
  CFAllocatorGetContext(alloc, &context);
  return (*(int *)(context.info));
}

Other Core Foundation functions invoke the memory-related callbacks defined in an allocator context and take or return an untyped pointer to a block of memory (void *):

CFAllocatorAllocate allocates a block of memory.
CFAllocatorReallocate reallocates a block of memory.
CFAllocatorDeallocate deallocates a block of memory.
CFAllocatorGetPreferredSizeForSize gives the size of memory likely to be allocated, given a certain request.

Creating Custom Allocators

To create a custom allocator, first declare and initialize a structure of type CFAllocatorContext.