[ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Top] | [Table des matières] | [Index] | [ ? ] |
The unwind-protect
construct is essential whenever you temporarily
put a data structure in an inconsistent state; it permits you to make the
data consistent again in the event of an error or throw. (Another more
specific cleanup construct that is used only for changes in buffer contents
is the atomic change group; Atomic Change Groups.)
unwind-protect
executes body-form with a guarantee that the
cleanup-forms will be evaluated if control leaves body-form, no
matter how that happens. body-form may complete normally, or execute
a throw
out of the unwind-protect
, or cause an error; in all
cases, the cleanup-forms will be evaluated.
If body-form finishes normally, unwind-protect
returns the
value of body-form, after it evaluates the cleanup-forms. If
body-form does not finish, unwind-protect
does not return any
value in the normal sense.
Only body-form is protected by the unwind-protect
. If any of
the cleanup-forms themselves exits nonlocally (via a throw
or
an error), unwind-protect
is not guaranteed to evaluate the
rest of them. If the failure of one of the cleanup-forms has the
potential to cause trouble, then protect it with another
unwind-protect
around that form.
The number of currently active unwind-protect
forms counts, together
with the number of local variable bindings, against the limit
max-specpdl-size
(voir Local Variables).
For example, here we make an invisible buffer for temporary use, and make sure to kill it before finishing:
(save-excursion (let ((buffer (get-buffer-create " *temp*"))) (set-buffer buffer) (unwind-protect body-form (kill-buffer buffer)))) |
You might think that we could just as well write (kill-buffer
(current-buffer))
and dispense with the variable buffer
. However,
the way shown above is safer, if body-form happens to get an error
after switching to a different buffer! (Alternatively, you could write
another save-excursion
around body-form, to ensure that the
temporary buffer becomes current again in time to kill it.)
Emacs includes a standard macro called with-temp-buffer
which expands
into more or less the code shown above (voir Current Buffer). Several of the macros defined in this
manual use unwind-protect
in this way.
Here is an actual example derived from an FTP package. It creates a process
(@pxref{Processes}) to try to establish a connection to a remote machine.
As the function ftp-login
is highly susceptible to numerous problems
that the writer of the function cannot anticipate, it is protected with a
form that guarantees deletion of the process in the event of failure.
Otherwise, Emacs might fill up with useless subprocesses.
(let ((win nil)) (unwind-protect (progn (setq process (ftp-setup-buffer host file)) (if (setq win (ftp-login process host user password)) (message "Logged in") (error "Ftp login failed"))) (or win (and process (delete-process process))))) |
This example has a small bug: if the user types C-g to quit, and the
quit happens immediately after the function ftp-setup-buffer
returns
but before the variable process
is set, the process will not be
killed. There is no easy way to fix this bug, but at least it is very
unlikely.
[ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Top] | [Table des matières] | [Index] | [ ? ] |
Ce document a été généré par Eric Reinbold le 13 Octobre 2007 en utilisant texi2html 1.78.