Clean Up When Functions Complete
Overview
A good programming practice is to make sure that you leave your program environment in a clean state that does not interfere with any other program code. For example, you might want to
Close any files that you opened for import or export.
Restore the MATLAB® path.
Lock or unlock memory to prevent or allow erasing MATLAB function or MEX-files.
Set your working folder back to its default if you have changed it.
Make sure global and persistent variables are in the correct state.
MATLAB provides the onCleanup
function for this purpose. This function, when used within
any program, establishes a cleanup routine for that function. When the function
terminates, whether normally or in the event of an error or Ctrl+C,
MATLAB automatically executes the cleanup routine.
The following statement establishes a cleanup routine
cleanupFun
for the currently running program:
cleanupObj = onCleanup(@cleanupFun);
When your program exits, MATLAB finds any instances of the onCleanup
class and
executes the associated function handles. The process of generating and activating
function cleanup involves the following steps:
Write one or more cleanup routines for the program under development. Assume for now that it takes only one such routine.
Create a function handle for the cleanup routine.
At some point, generally early in your program code, insert a call to the
onCleanup
function, passing the function handle.When the program is run, the call to
onCleanup
constructs a cleanup object that contains a handle to the cleanup routine created in step 1.When the program ends, MATLAB implicitly clears all objects that are local variables. This invokes the destructor method for each local object in your program, including the cleanup object constructed in step 4.
The destructor method for this object invokes this routine if it exists. This perform the tasks needed to restore your programming environment.
You can declare any number of cleanup routines for a program file. Each call to
onCleanup
establishes a separate cleanup routine for each
cleanup object returned.
If, for some reason, the object returned by onCleanup
persists beyond the life of your program, then the cleanup routine associated with
that object is not run when your function terminates. Instead, it will run whenever
the object is destroyed (e.g., by clearing the object variable).
Your cleanup routine should never rely on variables that are defined outside of
that routine. For example, the nested function shown here on the left executes with
no error, whereas the very similar one on the right fails with the error, Undefined function or variable 'k'
. This results
from the cleanup routine's reliance on variable k
which is
defined outside of the nested cleanup routine:
function testCleanup function testCleanup k = 3; k = 3; myFun obj = onCleanup(@myFun); function myFun function myFun fprintf('k is %d\n', k) fprintf('k is %d\n', k) end end end end
Examples of Cleaning Up a Program Upon Exit
Example 1 — Close Open Files on Exit
MATLAB closes the file with identifier fid
when
function openFileSafely
terminates:
function openFileSafely(fileName) fid = fopen(fileName, 'r'); c = onCleanup(@()fclose(fid)); s = fread(fid); . . . end
Example 2 — Maintain the Selected Folder
This example preserves the current folder whether
functionThatMayError
returns an error or not:
function changeFolderSafely(fileName) currentFolder = pwd; c = onCleanup(@()cd(currentFolder)); functionThatMayError; end % c executes cd(currentFolder) here.
Example 3 — Close Figure and Restore MATLAB Path
This example extends the MATLAB path to include files in the toolbox\images folders, and then
displays a figure from one of these folders. After the figure displays, the
cleanup routine restore_env
closes the figure and restores
the path to its original state.
function showImageOutsidePath(imageFile) fig1 = figure; imgpath = genpath([matlabroot '\toolbox\images']); % Define the cleanup routine. cleanupObj = onCleanup(@()restore_env(fig1, imgpath)); % Modify the path to gain access to the image file, % and display the image. addpath(imgpath); rgb = imread(imageFile); fprintf('\n Opening the figure %s\n', imageFile); image(rgb); pause(2); % This is the cleanup routine. function restore_env(fighandle, newpath) disp ' Closing the figure' close(fighandle); pause(2) disp ' Restoring the path' rmpath(newpath); end end
Run the function as shown here. You can verify that the path has been restored by comparing the length of the path before and after running the function:
origLen = length(path); showImageOutsidePath('greens.jpg') Opening the figure greens.jpg Closing the figure Restoring the path currLen = length(path); currLen == origLen ans = 1
Retrieving Information About the Cleanup Routine
In Example 3 shown above, the cleanup routine and data needed to call it are contained in a handle to an anonymous function:
@()restore_env(fig1, imgpath)
The details of that handle are then contained within the object returned by the
onCleanup
function:
cleanupObj = onCleanup(@()restore_env(fig1, imgpath));
You can access these details using the task
property of the
cleanup object as shown here. (Modify the showImageOutsidePath
function by adding the following code just before the comment line that says,
“% This is the cleanup
routine.
”)
disp ' Displaying information from the function handle:' task = cleanupObj.task; fun = functions(task) wsp = fun.workspace{2,1} fprintf('\n'); pause(2);
Run the modified function to see the output of the functions
command and the contents of one of the workspace
cells:
showImageOutsidePath('greens.jpg') Opening the figure greens.jpg Displaying information from the function handle: fun = function: '@()restore_env(fig1,imgpath)' type: 'anonymous' file: 'c:\work\g6.m' workspace: {2x1 cell} wsp = imageFile: 'greens.jpg' fig1: 1 imgpath: [1x3957 char] cleanupObj: [1x1 onCleanup] rgb: [300x500x3 uint8] task: @()restore_env(fig1,imgpath) Closing the figure Restoring the path
Using onCleanup Versus try/catch
Another way to run a cleanup routine when a function terminates unexpectedly is to
use a try, catch
statement. There are
limitations to using this technique however. If the user ends the program by typing
Ctrl+C, MATLAB immediately exits the try
block, and the cleanup
routine never executes. The cleanup routine also does not run when you exit the
function normally.
The following program cleans up if an error occurs, but not in response to Ctrl+C:
function cleanupByCatch try pause(10); catch disp(' Collecting information about the error') disp(' Executing cleanup tasks') end
Unlike the try/catch
statement, the
onCleanup
function responds not only to a normal exit from
your program and any error that might be thrown, but also to
Ctrl+C. This next example replaces the
try/catch
with onCleanup
:
function cleanupByFunc obj = onCleanup(@()... disp(' Executing cleanup tasks')); pause(10);
onCleanup in Scripts
onCleanup
does not work in scripts as it does in functions.
In functions, the cleanup object is stored in the function workspace. When the
function exits, this workspace is cleared thus executing the associated cleanup
routine. In scripts, the cleanup object is stored in the base workspace (that is,
the workspace used in interactive work done at the command prompt). Because exiting
a script has no effect on the base workspace, the cleanup object is not cleared and
the routine associated with that object does not execute. To use this type of
cleanup mechanism in a script, you would have to explicitly clear the object from
the command line or another script when the first script terminates.