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
onCleanupfunction, passing the function handle.When the program is run, the call to
onCleanupconstructs 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);
.
.
.
endExample 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
endRun 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 =
1Retrieving 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')
endUnlike 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.