Paul Eggert <[email protected]> writes:
> +struct allocator
> +{
> + /* Call MALLOC to allocate memory, like 'malloc'. On failure MALLOC
> + should return NULL, though not necessarily set errno. When given
> + a zero size it may return NULL even if successful. */
> + void *(*malloc) (size_t);
> +
> + /* If nonnull, call REALLOC to reallocate memory, like 'realloc'.
> + On failure REALLOC should return NULL, though not necessarily set
> + errno. When given a zero size it may return NULL even if
> + successful. */
> + void *(*realloc) (void *, size_t);
> +
> + /* Call FREE to free memory, like 'free'. */
> + void (*free) (void *);
> +
> + /* If nonnull, call DIE if MALLOC or REALLOC fails. DIE should
> + not return. */
> + void (*die) (void);
> +};
It might be a good idea to mark each function with appropriate
GCC attributes, e.g. __attribute__((malloc)) for malloc and
realloc and __attribute__((noreturn)) for die.
I was a little surprised to see the first proposed use of this
actually copy out all of the pointers into local variables. If
that's the way it's going to be used, I guess that would make
the attributes useless, unless they were applied to the local
variables too.
I'm not sure why die is a separate member. Couldn't xmalloc and
xrealloc simply be used as the malloc and realloc functions?
I would have guessed that there would be a global instance of
this allocator, something like:
struct allocator standard_allocator = { malloc, realloc, free, NULL };
and possibly another one that uses the x* functions:
struct allocator xstandard_allocator = { xmalloc, xrealloc, free, NULL };
or
struct allocator xstandard_allocator = { malloc, realloc, free, xalloc_die };
With global instances, functions can pass in one of those instead
of a null allocator, and then the functions that call into the
allocator don't have to have special cases.
--
Ben Pfaff
http://benpfaff.org