glib wraps the standard
malloc() and free() with
its own g_ variants,
g_malloc() and g_free(), shown in Figure 5. These are nice
in several small ways:
-
g_malloc() always returns
a gpointer, never a
char*, so there's
no need to cast the return value.
-
g_malloc() aborts the
program if the underlying
malloc() fails, so you don't have to check for
a NULL return
value.
-
g_malloc() gracefully
handles a size of
0, by returning
NULL.
-
g_free() will ignore any
NULL pointers you
pass to it.
In addition to these minor conveniences, g_malloc() and
g_free() can support various kinds of memory
debugging and profiling. If you pass the --enable-mem-check option to glib's
configure script, the compiled
g_free() will warn you whenever you free the same
pointer twice. The
--enable-mem-profile option enables code which
keeps memory use statistics; when you call g_mem_profile() they are printed to the
console. Finally, you can define USE_DMALLOC and the glib memory
wrappers will use the
MALLOC(), etc. debugging macros available in dmalloc.h on some platforms.
It's important to match
g_malloc() with
g_free(), plain malloc()
with free(), and (if you're
using C++) new with
delete. Otherwise bad
things can happen, since these allocators may use
different memory pools (and
new/delete call
constructors and destructors).
Of course there's a
g_realloc() equivalent to
realloc(). There's also a convenient g_malloc0() which fills allocated
memory with 0s, and
g_memdup() which returns a copy of bytesize bytes starting at mem.
g_realloc() and
g_malloc0() will both accept a size of
0, for consistency with g_malloc(). However, g_memdup() will not.
If it isn't obvious:
g_malloc0() fills raw memory with unset bits, not
the value 0 for
whatever type you intend to put there. Occasionally
someone expects to get an array of floating point
numbers initialized to
0.0; this will not work.
Finally, there are type-aware allocation macros, shown
in Figure 6. The
type argument to each
of these is the name of a type, and the count argument is the number of
type-size blocks to
allocate. These macros save you some typing and
multiplication, and are thus less error-prone. They
automatically cast to the target pointer type, so
attempting to assign the allocated memory to the wrong
kind of pointer should trigger a compiler warning. (If
you have warnings turned on, as a responsible
programmer should!)