Yes. Actually I want to dynamically allocate memory for pointers
contained in a struct and I'm looking for an easy way to release all
memory in case of malloc failure.
I know it is a bit remote with the starting topic of this thread, but
here is an example :
Please leave me your comments if you want.
[snip example]
You might find it worh the effort to put together a little storage
management utility that I call a storage pool kit. (No doubt there is
a better name.)
The basic idea is to refine the world's simplest storage allocator. It
works like this: We start with a block of unallocated storage and and
a pointer to the beginning of unallocated storage. When we get a
request for storage we return the current value of the pointer and
advance the pointer to the new start of unallocated storage. (But do
make allowance for alignment.) We never free anything - once storage
is allocated it stays allocated.
This scheme is simple and cheap; allocation is trivial and there are
no deallocation costs. Eventually it fails when all of the available
storage is allocated. Suppose, however, we have a series of
allocations that will/can all be released at the same time. Then our
primitive allocator works very well. As it happens, this is a very
common pattern. Your struct that holds pointers to arrays that must be
allocated in turn is a good example.
It turns out that there can be many such sequences in the code;
therefore it is better to have a separate storage pool for each such
sequence of allocations. The storage pool manager must have three
main entry points, open, get, and close. Open creates a storage pool
and returns a handle to the pool. Get gets a block of storage from a
given pool (specified by its handle). Finally, close frees all of the
malloced storage used by the pool and marks the handle as inactive.
The basic idea in the implementation is to use a linnked list of
buffers. When the current buffer is exhausted "get" gets a new muffer
from malloc and adds it to the list. Each new buffer is (a) large
enough to hold the request, and (b) larger than the previous buffer by
some factor. (I use 1.5, but 2 is okay too.)
As a note, the buffer free space pointer must always be an aligned
address.
I have an implementation of this kind of utility on the web. There is
a .c file and a .h file. They are at:
<
http://home.tiac.net/~cri_a/san/source_code/utl/src/stgpool.c>
<
http://home.tiac.net/~cri_a/san/source_code/utl/include/stgpool.h>
You probably don't want to use my implementation; it is part of a
package of utilities and has calls to other functions in the package.
However you can adapt the code to create your own stand alone version.
The needed modifications are pretty obvious.
The exception is error handling. There are three kinds of errors to
take into account. One is malloc failure. (In my version getspace
handles malloc failures.) A stand alone implementation should handle
malloc failures. The obvious thing to do is for "get" to call "close"
and then return a null pointer. This will free all of the buffers and
may inactive the pool handle.
The second kind of error is a faulty handle. It could be a stale
handle or something that was never a handle. Unfortunately the
reference implementation doesn't check for these kinds of errors; it
uses the "trust that the user gets it right" policy.
The final kind of error is a failure of the "open" function. This
could either be because of a bad argument or because of a memory
failure.
I will leave the issue of error handling as an open question.
Finally, I'm not really happy with the handle format but that is a
topic for another time.