| www.delorie.com/gnu/docs/gdb/gdbint_105.html | search |
![]() Buy the book! | |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Cleanups are a structured way to deal with things that need to be done later.
When your code does something (e.g., xmalloc some memory, or
open a file) that needs to be undone later (e.g., xfree
the memory or close the file), it can make a cleanup. The
cleanup will be done at some future point: when the command is finished
and control returns to the top level; when an error occurs and the stack
is unwound; or when your code decides it's time to explicitly perform
cleanups. Alternatively you can elect to discard the cleanups you
created.
Syntax:
struct cleanup *old_chain;
old_chain = make_cleanup (function, arg);
char *) later. The result, old_chain, is a
handle that can later be passed to do_cleanups or
discard_cleanups. Unless you are going to call
do_cleanups or discard_cleanups, you can ignore the result
from make_cleanup.
do_cleanups (old_chain);
make_cleanup call was made.
discard_cleanups (old_chain);
do_cleanups except that it just removes the cleanups from
the chain and does not call the specified functions.
Cleanups are implemented as a chain. The handle returned by
make_cleanups includes the cleanup passed to the call and any
later cleanups appended to the chain (but not yet discarded or
performed). E.g.:
make_cleanup (a, 0);
{
struct cleanup *old = make_cleanup (b, 0);
make_cleanup (c, 0)
...
do_cleanups (old);
}
|
will call c() and b() but will not call a(). The
cleanup that calls a() will remain in the cleanup chain, and will
be done later unless otherwise discarded.
Your function should explicitly do or discard the cleanups it creates. Failing to do this leads to non-deterministic behavior since the caller will arbitrarily do or discard your functions cleanups. This need leads to two common cleanup styles.
The first style is try/finally. Before it exits, your code-block calls
do_cleanups with the old cleanup chain and thus ensures that your
code-block's cleanups are always performed. For instance, the following
code-segment avoids a memory leak problem (even when error is
called and a forced stack unwind occurs) by ensuring that the
xfree will always be called:
struct cleanup *old = make_cleanup (null_cleanup, 0); data = xmalloc (sizeof blah); make_cleanup (xfree, data); ... blah blah ... do_cleanups (old); |
The second style is try/except. Before it exits, your code-block calls
discard_cleanups with the old cleanup chain and thus ensures that
any created cleanups are not performed. For instance, the following
code segment, ensures that the file will be closed but only if there is
an error:
FILE *file = fopen ("afile", "r");
struct cleanup *old = make_cleanup (close_file, file);
... blah blah ...
discard_cleanups (old);
return file;
|
Some functions, e.g. fputs_filtered() or error(), specify
that they "should not be called when cleanups are not in place". This
means that any actions you need to reverse in the case of an error or
interruption must be on the cleanup chain before you call these
functions, since they might never return to your code (they
`longjmp' instead).
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
| webmaster donations bookstore | delorie software privacy |
| Copyright © 2003 by The Free Software Foundation | Updated Jun 2003 |