カスタムアロケータの作成
カスタムアロケータを作成するには、まず CFAllocatorContext 型の構造体を宣言して初期化します。バージョンフィールドを 0 に初期化し、制御情報などの任意のデータを割り当てて info フィールドに指定します。この構造体の他のフィールドは、後述の アロケータ呼び出し関数の実装 で説明している関数ポインタです。
CFAllocatorContext 構造体のフィールドに適切な値を割り当てたら、CFAllocatorCreate 関数を呼び出してアロケータ・オブジェクトを作成します。この関数の第 2 パラメータは構造体へのポインタです。この関数の最初のパラメータは、新しいオブジェクトにメモリを割り当てるために使用するアロケータを識別します。この目的のために CFAllocateContext 構造体の allocate 呼び出し関数を使用する場合は、最初のパラメータに kCFAllocatorUseContext 定数を指定します。デフォルトのアロケータを使用する場合は、このパラメータに NULL を指定します。
リスト 1 : カスタムアロケータの作成
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; }
アロケータ呼び出し関数の実装
CFAllocatorContext 構造体には、呼び出し関数を定義する 7 つのフィールドがあります。カスタムアロケータを作成する場合は、少なくとも allocate 関数を実装しなければなりません。アロケータ呼び出し関数はスレッドセーフでなければならず、呼び出し関数が他の関数を呼び出す場合は、リエントラントである必要があります。
retain、release、および copy-description 呼び出し関数(callbacks)はすべて、CFAllocatorContext 構造体の info フィールドを 1 つの引数として取ります。void * と型付けされると、このフィールドは、制御情報を含む構造体など、アロケータ用に定義した任意のデータを指します。
Retain Callback:
const void *(*retain)(const void *info);
アロケータコンテキスト用に定義したデータを info に保持します。これは、データが Core Foundation オブジェクトである場合にのみ意味を持ちます。この関数ポインタを NULL に設定できます。
Release Callback:
void (*release)(const void *info);
アロケータ・コンテキスト用に定義したデータを解放(または自由に) します。この関数ポインタを NULL に設定することもできますが、そうするとメモリリークが発生する可能性があります。
Copy Description Callback:
CFStringRef (*copyDescription)(const void *info);
アロケータを記述する CFString への参照、特にユーザ定義データのいくつかの特性を返します。この関数ポインタを NULL に設定できます。その場合、Core Foundation は基本的な説明を提供します。
Allocate Callback:
void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info);
少なくとも size バイトのメモリブロックを割り当て、ブロックの先頭にポインタを戻します。hint 引数は、現在使用してはいけないビットフィールドです。size パラメータは常に 0 より大きくなければなりません。そうでない場合、または割り当てに問題が発生した場合は NULL を返します。この呼び出し関数 (callback) は NULL でなくてもかまいません。
Reallocate Callback:
void * (*reallocate)(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info);
ptr が指すメモリブロックのサイズを newsize で指定されたサイズに変更し、ポインタを大きなメモリブロックに戻します。再配置の失敗時には NULL を返し、古いメモリブロックはそのまま残します。ptr パラメータは決して NULL になることはなく、newsize は常に 0 より大きいことに注意してください。この 2 つの条件が満たされない限り、この呼び出し関数は使用されません。
古いメモリブロックの内容は新しいサイズまたは古いサイズのうちの小さいものに変更しないでください。ptr パラメータが、アロケータによって以前に割り当てられたメモリのブロックでない場合、結果は未定義です。異常なプログラムの終了が発生する可能性があります。2hint 引数は、現在使用してはいけないビットフィールドです。この呼び出し関数を NULL に設定すると、CFAllocatorReallocate 関数はこのアロケータを使用しようとするとほとんどの場合 NULL を返します。
Deallocate Callback:
void (*deallocate)(void *ptr, void *info);
ptr が指すメモリブロックをアロケータによる後続の再利用に利用できるようにしますが、プログラムにより、引き続き使用することはできません。ptr パラメータは NULL にすることはできず、ptr パラメータが、アロケータによって以前に割り当てられたメモリブロックでない場合、結果は未定義です。異常なプログラム終了が発生する可能性があります。この呼び出し関数を NULL に設定できます。この場合、CFAllocatorDeallocate 関数は無効です。
Preferred Size Callback:
CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);
サイズ size のメモリブロックに対する要求がある場合、アロケータが割り当てる可能性のある実際のサイズを返します。hint 引数は、現在使用してはいけないビットフィールドです。
前の章 次の章